diff options
Diffstat (limited to 'apps/shorty')
150 files changed, 11793 insertions, 0 deletions
diff --git a/apps/shorty/.htaccess b/apps/shorty/.htaccess new file mode 100644 index 00000000000..b7c4189ae49 --- /dev/null +++ b/apps/shorty/.htaccess @@ -0,0 +1,45 @@ +# +# @package shorty an ownCloud url shortener plugin +# @category internet +# @author Christian Reiner +# @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +# @license GNU Affero General Public license (AGPL) +# @link information +# @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +# License as published by the Free Software Foundation; either +# version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +# +# You should have received a copy of the GNU Affero General Public +# License along with this library. +# If not, see <http://www.gnu.org/licenses/>. +# + +# @file .htaccess +# These rules try to detect any requests that carry a "shorty id" and map them to forward.php?<shorty id> +# That way you can use shorter (or more simple) urls to publish or relay links +# @author Christian Reiner + +RewriteEngine On + +# example: http://.../apps/shorty/index.php/0123456789 +RewriteRule index\.php/([a-z0-9]{4,12})$ ../../public.php?service=shorty_relay&id=$1 [NC,L] + +# example: http://.../apps/shorty/index.php?0123456789 +RewriteCond %{QUERY_STRING} ^([a-z0-9]{4,12})$ [NC] +RewriteRule index\.php ../../public.php?service=shorty_relay&id=%{QUERY_STRING} [L] + +# example: http://.../apps/shorty/?0123456789 +RewriteCond %{QUERY_STRING} ^([a-z0-9]{4,12})$ [NC] +RewriteCond %{REQUEST_URI} meta/.+\.php +RewriteRule - ../../public.php?service=shorty_relay&id=%{QUERY_STRING} [L] + +# example: http://.../apps/shorty/0123456789 +RewriteRule ^([a-z0-9]{4,12})$ ../../public.php?service=shorty_relay&id=$1 [NC,L] diff --git a/apps/shorty/3rdparty/js/jquery.tinysort.min.js b/apps/shorty/3rdparty/js/jquery.tinysort.min.js new file mode 100644 index 00000000000..225f799ca9d --- /dev/null +++ b/apps/shorty/3rdparty/js/jquery.tinysort.min.js @@ -0,0 +1 @@ +(function(b){var o=!1,d=null,u=parseFloat,j=String.fromCharCode,q=Math.min,l=/(\d+\.?\d*)$/g,g,a=[],h,m,t=9472,f={},c;for(var p=32,k=j(p),r=255;p<r;p++,k=j(p).toLowerCase()){if(!~a.indexOf(k)){a.push(k)}}a.sort();b.tinysort={id:"TinySort",version:"1.3.20",copyright:"Copyright (c) 2008-2012 Ron Valstar",uri:"http://tinysort.sjeiti.com/",licenced:{MIT:"http://www.opensource.org/licenses/mit-license.php",GPL:"http://www.gnu.org/licenses/gpl.html"},defaults:{order:"asc",attr:d,data:d,useVal:o,place:"start",returns:o,cases:o,forceStrings:o,sortFunction:d,charOrder:g}};b.fn.extend({tinysort:function(V,L){if(V&&typeof(V)!="string"){L=V;V=d}var T=b.extend({},b.tinysort.defaults,L),v,Q=this,z=b(this).length,ae={},W=!(!V||V==""),H=!(T.attr===d||T.attr==""),ah=T.data!==d,J=W&&V[0]==":",C=J?Q.filter(V):Q,F=T.sortFunction,s=T.order=="asc"?1:-1,P=[];if(T.charOrder!=g){g=T.charOrder;if(!T.charOrder){m=false;t=9472;f={};c=h=d}else{h=a.slice(0);m=false;for(var S=[],B=function(i,ai){S.push(ai);f[T.cases?i:i.toLowerCase()]=ai},N="",X="z",aa=g.length,ac,Z,ad=0;ad<aa;ad++){var x=g[ad],ab=x.charCodeAt(),I=ab>96&&ab<123;if(!I){if(x=="["){var D=S.length,M=D?S[D-1]:X,w=g.substr(ad+1).match(/[^\]]*/)[0],R=w.match(/{[^}]*}/g);if(R){for(ac=0,Z=R.length;ac<Z;ac++){var O=R[ac];ad+=O.length;w=w.replace(O,"");B(O.replace(/[{}]/g,""),M);m=true}}for(ac=0,Z=w.length;ac<Z;ac++){B(M,w[ac])}ad+=w.length+1}else{if(x=="{"){var G=g.substr(ad+1).match(/[^}]*/)[0];B(G,j(t++));ad+=G.length+1;m=true}else{S.push(x)}}}if(S.length&&(I||ad===aa-1)){var E=S.join("");N+=E;b.each(E,function(i,ai){h.splice(h.indexOf(ai),1)});var A=S.slice(0);A.splice(0,0,h.indexOf(X)+1,0);Array.prototype.splice.apply(h,A);S.length=0}if(ad+1===aa){c=new RegExp("["+N+"]","gi")}else{if(I){X=x}}}}}if(!F){F=T.order=="rand"?function(){return Math.random()<0.5?1:-1}:function(av,at){var au=o,am=!T.cases?n(av.s):av.s,ak=!T.cases?n(at.s):at.s;if(!T.forceStrings){var aj=am&&am.match(l),aw=ak&&ak.match(l);if(aj&&aw){var ar=am.substr(0,am.length-aj[0].length),aq=ak.substr(0,ak.length-aw[0].length);if(ar==aq){au=!o;am=u(aj[0]);ak=u(aw[0])}}}var ai=s*(am<ak?-1:(am>ak?1:0));if(!au&&T.charOrder){if(m){for(var ax in f){var al=f[ax];am=am.replace(ax,al);ak=ak.replace(ax,al)}}if(am.match(c)!==d||ak.match(c)!==d){for(var ap=0,ao=q(am.length,ak.length);ap<ao;ap++){var an=h.indexOf(am[ap]),i=h.indexOf(ak[ap]);if(ai=s*(an<i?-1:(an>i?1:0))){break}}}}return ai}}Q.each(function(ak,al){var am=b(al),ai=W?(J?C.filter(al):am.find(V)):am,an=ah?ai.data(T.data):(H?ai.attr(T.attr):(T.useVal?ai.val():ai.text())),aj=am.parent();if(!ae[aj]){ae[aj]={s:[],n:[]}}if(ai.length>0){ae[aj].s.push({s:an,e:am,n:ak})}else{ae[aj].n.push({e:am,n:ak})}});for(v in ae){ae[v].s.sort(F)}for(v in ae){var ag=ae[v],K=[],Y=z,af=[0,0],ad;switch(T.place){case"first":b.each(ag.s,function(ai,aj){Y=q(Y,aj.n)});break;case"org":b.each(ag.s,function(ai,aj){K.push(aj.n)});break;case"end":Y=ag.n.length;break;default:Y=0}for(ad=0;ad<z;ad++){var y=e(K,ad)?!o:ad>=Y&&ad<Y+ag.s.length,U=(y?ag.s:ag.n)[af[y?0:1]].e;U.parent().append(U);if(y||!T.returns){P.push(U.get(0))}af[y?0:1]++}}Q.length=0;Array.prototype.push.apply(Q,P);return Q}});function n(i){return i&&i.toLowerCase?i.toLowerCase():i}function e(v,x){for(var w=0,s=v.length;w<s;w++){if(v[w]==x){return !o}}return o}b.fn.TinySort=b.fn.Tinysort=b.fn.tsort=b.fn.tinysort})(jQuery);
\ No newline at end of file diff --git a/apps/shorty/3rdparty/php/phpqrcode.php b/apps/shorty/3rdparty/php/phpqrcode.php new file mode 100644 index 00000000000..80adb9df239 --- /dev/null +++ b/apps/shorty/3rdparty/php/phpqrcode.php @@ -0,0 +1,3312 @@ +<?php
+
+/*
+ * PHP QR Code encoder
+ *
+ * This file contains MERGED version of PHP QR Code library.
+ * It was auto-generated from full version for your convenience.
+ *
+ * This merged version was configured to not requre any external files,
+ * with disabled cache, error loging and weker but faster mask matching.
+ * If you need tune it up please use non-merged version.
+ *
+ * For full version, documentation, examples of use please visit:
+ *
+ * http://phpqrcode.sourceforge.net/
+ * https://sourceforge.net/projects/phpqrcode/
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ + +/* + * Version: 1.1.4 + * Build: 2010100721 + */ + + + +//---- qrconst.php ----------------------------- + + + +
+
+/*
+ * PHP QR Code encoder
+ *
+ * Common constants
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ // Encoding modes
+
+ define('QR_MODE_NUL', -1);
+ define('QR_MODE_NUM', 0);
+ define('QR_MODE_AN', 1);
+ define('QR_MODE_8', 2);
+ define('QR_MODE_KANJI', 3);
+ define('QR_MODE_STRUCTURE', 4);
+
+ // Levels of error correction.
+
+ define('QR_ECLEVEL_L', 0);
+ define('QR_ECLEVEL_M', 1);
+ define('QR_ECLEVEL_Q', 2);
+ define('QR_ECLEVEL_H', 3);
+
+ // Supported output formats
+
+ define('QR_FORMAT_TEXT', 0);
+ define('QR_FORMAT_PNG', 1);
+
+ class qrstr {
+ public static function set(&$srctab, $x, $y, $repl, $replLen = false) {
+ $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
+ }
+ } + + + +//---- merged_config.php ----------------------------- + + + +
+/*
+ * PHP QR Code encoder
+ *
+ * Config file, tuned-up for merged verion
+ */
+
+ define('QR_CACHEABLE', false); // use cache - more disk reads but less CPU power, masks and format templates are stored there
+ define('QR_CACHE_DIR', false); // used when QR_CACHEABLE === true
+ define('QR_LOG_DIR', false); // default error logs dir
+
+ define('QR_FIND_BEST_MASK', true); // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
+ define('QR_FIND_FROM_RANDOM', 2); // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
+ define('QR_DEFAULT_MASK', 2); // when QR_FIND_BEST_MASK === false
+
+ define('QR_PNG_MAXIMUM_SIZE', 1024); // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images
+ + + + +//---- qrtools.php ----------------------------- + + + +
+/*
+ * PHP QR Code encoder
+ *
+ * Toolset, handy and debug utilites.
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ class QRtools {
+
+ //----------------------------------------------------------------------
+ public static function binarize($frame)
+ {
+ $len = count($frame);
+ foreach ($frame as &$frameLine) {
+
+ for($i=0; $i<$len; $i++) {
+ $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
+ }
+ }
+
+ return $frame;
+ }
+
+ //----------------------------------------------------------------------
+ public static function tcpdfBarcodeArray($code, $mode = 'QR,L', $tcPdfVersion = '4.5.037')
+ {
+ $barcode_array = array();
+
+ if (!is_array($mode))
+ $mode = explode(',', $mode);
+
+ $eccLevel = 'L';
+
+ if (count($mode) > 1) {
+ $eccLevel = $mode[1];
+ }
+
+ $qrTab = QRcode::text($code, false, $eccLevel);
+ $size = count($qrTab);
+
+ $barcode_array['num_rows'] = $size;
+ $barcode_array['num_cols'] = $size;
+ $barcode_array['bcode'] = array();
+
+ foreach ($qrTab as $line) {
+ $arrAdd = array();
+ foreach(str_split($line) as $char)
+ $arrAdd[] = ($char=='1')?1:0;
+ $barcode_array['bcode'][] = $arrAdd;
+ }
+
+ return $barcode_array;
+ }
+
+ //----------------------------------------------------------------------
+ public static function clearCache()
+ {
+ self::$frames = array();
+ }
+
+ //----------------------------------------------------------------------
+ public static function buildCache()
+ {
+ QRtools::markTime('before_build_cache');
+
+ $mask = new QRmask();
+ for ($a=1; $a <= QRSPEC_VERSION_MAX; $a++) {
+ $frame = QRspec::newFrame($a);
+ if (QR_IMAGE) {
+ $fileName = QR_CACHE_DIR.'frame_'.$a.'.png';
+ QRimage::png(self::binarize($frame), $fileName, 1, 0);
+ }
+
+ $width = count($frame);
+ $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
+ for ($maskNo=0; $maskNo<8; $maskNo++)
+ $mask->makeMaskNo($maskNo, $width, $frame, $bitMask, true);
+ }
+
+ QRtools::markTime('after_build_cache');
+ }
+
+ //----------------------------------------------------------------------
+ public static function log($outfile, $err)
+ {
+ if (QR_LOG_DIR !== false) {
+ if ($err != '') {
+ if ($outfile !== false) {
+ file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
+ } else {
+ file_put_contents(QR_LOG_DIR.'errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
+ }
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public static function dumpMask($frame)
+ {
+ $width = count($frame);
+ for($y=0;$y<$width;$y++) {
+ for($x=0;$x<$width;$x++) {
+ echo ord($frame[$y][$x]).',';
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public static function markTime($markerId)
+ {
+ list($usec, $sec) = explode(" ", microtime());
+ $time = ((float)$usec + (float)$sec);
+
+ if (!isset($GLOBALS['qr_time_bench']))
+ $GLOBALS['qr_time_bench'] = array();
+
+ $GLOBALS['qr_time_bench'][$markerId] = $time;
+ }
+
+ //----------------------------------------------------------------------
+ public static function timeBenchmark()
+ {
+ self::markTime('finish');
+
+ $lastTime = 0;
+ $startTime = 0;
+ $p = 0;
+
+ echo '<table cellpadding="3" cellspacing="1">
+ <thead><tr style="border-bottom:1px solid silver"><td colspan="2" style="text-align:center">BENCHMARK</td></tr></thead>
+ <tbody>';
+
+ foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) {
+ if ($p > 0) {
+ echo '<tr><th style="text-align:right">till '.$markerId.': </th><td>'.number_format($thisTime-$lastTime, 6).'s</td></tr>';
+ } else {
+ $startTime = $thisTime;
+ }
+
+ $p++;
+ $lastTime = $thisTime;
+ }
+
+ echo '</tbody><tfoot>
+ <tr style="border-top:2px solid black"><th style="text-align:right">TOTAL: </th><td>'.number_format($lastTime-$startTime, 6).'s</td></tr>
+ </tfoot>
+ </table>';
+ }
+
+ }
+
+ //##########################################################################
+
+ QRtools::markTime('start');
+ + + + +//---- qrspec.php ----------------------------- + + + +
+/*
+ * PHP QR Code encoder
+ *
+ * QR Code specifications
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * The following data / specifications are taken from
+ * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
+ * or
+ * "Automatic identification and data capture techniques --
+ * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ define('QRSPEC_VERSION_MAX', 40);
+ define('QRSPEC_WIDTH_MAX', 177);
+
+ define('QRCAP_WIDTH', 0);
+ define('QRCAP_WORDS', 1);
+ define('QRCAP_REMINDER', 2);
+ define('QRCAP_EC', 3);
+
+ class QRspec {
+
+ public static $capacity = array(
+ array( 0, 0, 0, array( 0, 0, 0, 0)),
+ array( 21, 26, 0, array( 7, 10, 13, 17)), // 1
+ array( 25, 44, 7, array( 10, 16, 22, 28)),
+ array( 29, 70, 7, array( 15, 26, 36, 44)),
+ array( 33, 100, 7, array( 20, 36, 52, 64)),
+ array( 37, 134, 7, array( 26, 48, 72, 88)), // 5
+ array( 41, 172, 7, array( 36, 64, 96, 112)),
+ array( 45, 196, 0, array( 40, 72, 108, 130)),
+ array( 49, 242, 0, array( 48, 88, 132, 156)),
+ array( 53, 292, 0, array( 60, 110, 160, 192)),
+ array( 57, 346, 0, array( 72, 130, 192, 224)), //10
+ array( 61, 404, 0, array( 80, 150, 224, 264)),
+ array( 65, 466, 0, array( 96, 176, 260, 308)),
+ array( 69, 532, 0, array( 104, 198, 288, 352)),
+ array( 73, 581, 3, array( 120, 216, 320, 384)),
+ array( 77, 655, 3, array( 132, 240, 360, 432)), //15
+ array( 81, 733, 3, array( 144, 280, 408, 480)),
+ array( 85, 815, 3, array( 168, 308, 448, 532)),
+ array( 89, 901, 3, array( 180, 338, 504, 588)),
+ array( 93, 991, 3, array( 196, 364, 546, 650)),
+ array( 97, 1085, 3, array( 224, 416, 600, 700)), //20
+ array(101, 1156, 4, array( 224, 442, 644, 750)),
+ array(105, 1258, 4, array( 252, 476, 690, 816)),
+ array(109, 1364, 4, array( 270, 504, 750, 900)),
+ array(113, 1474, 4, array( 300, 560, 810, 960)),
+ array(117, 1588, 4, array( 312, 588, 870, 1050)), //25
+ array(121, 1706, 4, array( 336, 644, 952, 1110)),
+ array(125, 1828, 4, array( 360, 700, 1020, 1200)),
+ array(129, 1921, 3, array( 390, 728, 1050, 1260)),
+ array(133, 2051, 3, array( 420, 784, 1140, 1350)),
+ array(137, 2185, 3, array( 450, 812, 1200, 1440)), //30
+ array(141, 2323, 3, array( 480, 868, 1290, 1530)),
+ array(145, 2465, 3, array( 510, 924, 1350, 1620)),
+ array(149, 2611, 3, array( 540, 980, 1440, 1710)),
+ array(153, 2761, 3, array( 570, 1036, 1530, 1800)),
+ array(157, 2876, 0, array( 570, 1064, 1590, 1890)), //35
+ array(161, 3034, 0, array( 600, 1120, 1680, 1980)),
+ array(165, 3196, 0, array( 630, 1204, 1770, 2100)),
+ array(169, 3362, 0, array( 660, 1260, 1860, 2220)),
+ array(173, 3532, 0, array( 720, 1316, 1950, 2310)),
+ array(177, 3706, 0, array( 750, 1372, 2040, 2430)) //40
+ );
+
+ //----------------------------------------------------------------------
+ public static function getDataLength($version, $level)
+ {
+ return self::$capacity[$version][QRCAP_WORDS] - self::$capacity[$version][QRCAP_EC][$level];
+ }
+
+ //----------------------------------------------------------------------
+ public static function getECCLength($version, $level)
+ {
+ return self::$capacity[$version][QRCAP_EC][$level];
+ }
+
+ //----------------------------------------------------------------------
+ public static function getWidth($version)
+ {
+ return self::$capacity[$version][QRCAP_WIDTH];
+ }
+
+ //----------------------------------------------------------------------
+ public static function getRemainder($version)
+ {
+ return self::$capacity[$version][QRCAP_REMINDER];
+ }
+
+ //----------------------------------------------------------------------
+ public static function getMinimumVersion($size, $level)
+ {
+
+ for($i=1; $i<= QRSPEC_VERSION_MAX; $i++) {
+ $words = self::$capacity[$i][QRCAP_WORDS] - self::$capacity[$i][QRCAP_EC][$level];
+ if($words >= $size)
+ return $i;
+ }
+
+ return -1;
+ }
+
+ //######################################################################
+
+ public static $lengthTableBits = array(
+ array(10, 12, 14),
+ array( 9, 11, 13),
+ array( 8, 16, 16),
+ array( 8, 10, 12)
+ );
+
+ //----------------------------------------------------------------------
+ public static function lengthIndicator($mode, $version)
+ {
+ if ($mode == QR_MODE_STRUCTURE)
+ return 0;
+
+ if ($version <= 9) {
+ $l = 0;
+ } else if ($version <= 26) {
+ $l = 1;
+ } else {
+ $l = 2;
+ }
+
+ return self::$lengthTableBits[$mode][$l];
+ }
+
+ //----------------------------------------------------------------------
+ public static function maximumWords($mode, $version)
+ {
+ if($mode == QR_MODE_STRUCTURE)
+ return 3;
+
+ if($version <= 9) {
+ $l = 0;
+ } else if($version <= 26) {
+ $l = 1;
+ } else {
+ $l = 2;
+ }
+
+ $bits = self::$lengthTableBits[$mode][$l];
+ $words = (1 << $bits) - 1;
+
+ if($mode == QR_MODE_KANJI) {
+ $words *= 2; // the number of bytes is required
+ }
+
+ return $words;
+ }
+
+ // Error correction code -----------------------------------------------
+ // Table of the error correction code (Reed-Solomon block)
+ // See Table 12-16 (pp.30-36), JIS X0510:2004.
+
+ public static $eccTable = array(
+ array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)),
+ array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // 1
+ array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)),
+ array(array( 1, 0), array( 1, 0), array( 2, 0), array( 2, 0)),
+ array(array( 1, 0), array( 2, 0), array( 2, 0), array( 4, 0)),
+ array(array( 1, 0), array( 2, 0), array( 2, 2), array( 2, 2)), // 5
+ array(array( 2, 0), array( 4, 0), array( 4, 0), array( 4, 0)),
+ array(array( 2, 0), array( 4, 0), array( 2, 4), array( 4, 1)),
+ array(array( 2, 0), array( 2, 2), array( 4, 2), array( 4, 2)),
+ array(array( 2, 0), array( 3, 2), array( 4, 4), array( 4, 4)),
+ array(array( 2, 2), array( 4, 1), array( 6, 2), array( 6, 2)), //10
+ array(array( 4, 0), array( 1, 4), array( 4, 4), array( 3, 8)),
+ array(array( 2, 2), array( 6, 2), array( 4, 6), array( 7, 4)),
+ array(array( 4, 0), array( 8, 1), array( 8, 4), array(12, 4)),
+ array(array( 3, 1), array( 4, 5), array(11, 5), array(11, 5)),
+ array(array( 5, 1), array( 5, 5), array( 5, 7), array(11, 7)), //15
+ array(array( 5, 1), array( 7, 3), array(15, 2), array( 3, 13)),
+ array(array( 1, 5), array(10, 1), array( 1, 15), array( 2, 17)),
+ array(array( 5, 1), array( 9, 4), array(17, 1), array( 2, 19)),
+ array(array( 3, 4), array( 3, 11), array(17, 4), array( 9, 16)),
+ array(array( 3, 5), array( 3, 13), array(15, 5), array(15, 10)), //20
+ array(array( 4, 4), array(17, 0), array(17, 6), array(19, 6)),
+ array(array( 2, 7), array(17, 0), array( 7, 16), array(34, 0)),
+ array(array( 4, 5), array( 4, 14), array(11, 14), array(16, 14)),
+ array(array( 6, 4), array( 6, 14), array(11, 16), array(30, 2)),
+ array(array( 8, 4), array( 8, 13), array( 7, 22), array(22, 13)), //25
+ array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)),
+ array(array( 8, 4), array(22, 3), array( 8, 26), array(12, 28)),
+ array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)),
+ array(array( 7, 7), array(21, 7), array( 1, 37), array(19, 26)),
+ array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), //30
+ array(array(13, 3), array( 2, 29), array(42, 1), array(23, 28)),
+ array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)),
+ array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)),
+ array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)),
+ array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), //35
+ array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)),
+ array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)),
+ array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)),
+ array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)),
+ array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)),//40
+ );
+
+ //----------------------------------------------------------------------
+ // CACHEABLE!!!
+
+ public static function getEccSpec($version, $level, array &$spec)
+ {
+ if (count($spec) < 5) {
+ $spec = array(0,0,0,0,0);
+ }
+
+ $b1 = self::$eccTable[$version][$level][0];
+ $b2 = self::$eccTable[$version][$level][1];
+ $data = self::getDataLength($version, $level);
+ $ecc = self::getECCLength($version, $level);
+
+ if($b2 == 0) {
+ $spec[0] = $b1;
+ $spec[1] = (int)($data / $b1);
+ $spec[2] = (int)($ecc / $b1);
+ $spec[3] = 0;
+ $spec[4] = 0;
+ } else {
+ $spec[0] = $b1;
+ $spec[1] = (int)($data / ($b1 + $b2));
+ $spec[2] = (int)($ecc / ($b1 + $b2));
+ $spec[3] = $b2;
+ $spec[4] = $spec[1] + 1;
+ }
+ }
+
+ // Alignment pattern ---------------------------------------------------
+
+ // Positions of alignment patterns.
+ // This array includes only the second and the third position of the
+ // alignment patterns. Rest of them can be calculated from the distance
+ // between them.
+
+ // See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
+
+ public static $alignmentPattern = array(
+ array( 0, 0),
+ array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5
+ array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10
+ array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), //11-15
+ array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), //16-20
+ array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), //21-25
+ array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), //26-30
+ array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), //31-35
+ array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58), //35-40
+ );
+
+
+ /** --------------------------------------------------------------------
+ * Put an alignment marker.
+ * @param frame
+ * @param width
+ * @param ox,oy center coordinate of the pattern
+ */
+ public static function putAlignmentMarker(array &$frame, $ox, $oy)
+ {
+ $finder = array(
+ "\xa1\xa1\xa1\xa1\xa1",
+ "\xa1\xa0\xa0\xa0\xa1",
+ "\xa1\xa0\xa1\xa0\xa1",
+ "\xa1\xa0\xa0\xa0\xa1",
+ "\xa1\xa1\xa1\xa1\xa1"
+ );
+
+ $yStart = $oy-2;
+ $xStart = $ox-2;
+
+ for($y=0; $y<5; $y++) {
+ QRstr::set($frame, $xStart, $yStart+$y, $finder[$y]);
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public static function putAlignmentPattern($version, &$frame, $width)
+ {
+ if($version < 2)
+ return;
+
+ $d = self::$alignmentPattern[$version][1] - self::$alignmentPattern[$version][0];
+ if($d < 0) {
+ $w = 2;
+ } else {
+ $w = (int)(($width - self::$alignmentPattern[$version][0]) / $d + 2);
+ }
+
+ if($w * $w - 3 == 1) {
+ $x = self::$alignmentPattern[$version][0];
+ $y = self::$alignmentPattern[$version][0];
+ self::putAlignmentMarker($frame, $x, $y);
+ return;
+ }
+
+ $cx = self::$alignmentPattern[$version][0];
+ for($x=1; $x<$w - 1; $x++) {
+ self::putAlignmentMarker($frame, 6, $cx);
+ self::putAlignmentMarker($frame, $cx, 6);
+ $cx += $d;
+ }
+
+ $cy = self::$alignmentPattern[$version][0];
+ for($y=0; $y<$w-1; $y++) {
+ $cx = self::$alignmentPattern[$version][0];
+ for($x=0; $x<$w-1; $x++) {
+ self::putAlignmentMarker($frame, $cx, $cy);
+ $cx += $d;
+ }
+ $cy += $d;
+ }
+ }
+
+ // Version information pattern -----------------------------------------
+
+ // Version information pattern (BCH coded).
+ // See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
+
+ // size: [QRSPEC_VERSION_MAX - 6]
+
+ public static $versionPattern = array(
+ 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,
+ 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,
+ 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
+ 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,
+ 0x27541, 0x28c69
+ );
+
+ //----------------------------------------------------------------------
+ public static function getVersionPattern($version)
+ {
+ if($version < 7 || $version > QRSPEC_VERSION_MAX)
+ return 0;
+
+ return self::$versionPattern[$version -7];
+ }
+
+ // Format information --------------------------------------------------
+ // See calcFormatInfo in tests/test_qrspec.c (orginal qrencode c lib)
+
+ public static $formatInfo = array(
+ array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976),
+ array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0),
+ array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed),
+ array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)
+ );
+
+ public static function getFormatInfo($mask, $level)
+ {
+ if($mask < 0 || $mask > 7)
+ return 0;
+
+ if($level < 0 || $level > 3)
+ return 0;
+
+ return self::$formatInfo[$level][$mask];
+ }
+
+ // Frame ---------------------------------------------------------------
+ // Cache of initial frames.
+
+ public static $frames = array();
+
+ /** --------------------------------------------------------------------
+ * Put a finder pattern.
+ * @param frame
+ * @param width
+ * @param ox,oy upper-left coordinate of the pattern
+ */
+ public static function putFinderPattern(&$frame, $ox, $oy)
+ {
+ $finder = array(
+ "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
+ "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
+ "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
+ "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
+ "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
+ "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
+ "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
+ );
+
+ for($y=0; $y<7; $y++) {
+ QRstr::set($frame, $ox, $oy+$y, $finder[$y]);
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public static function createFrame($version)
+ {
+ $width = self::$capacity[$version][QRCAP_WIDTH];
+ $frameLine = str_repeat ("\0", $width);
+ $frame = array_fill(0, $width, $frameLine);
+
+ // Finder pattern
+ self::putFinderPattern($frame, 0, 0);
+ self::putFinderPattern($frame, $width - 7, 0);
+ self::putFinderPattern($frame, 0, $width - 7);
+
+ // Separator
+ $yOffset = $width - 7;
+
+ for($y=0; $y<7; $y++) {
+ $frame[$y][7] = "\xc0";
+ $frame[$y][$width - 8] = "\xc0";
+ $frame[$yOffset][7] = "\xc0";
+ $yOffset++;
+ }
+
+ $setPattern = str_repeat("\xc0", 8);
+
+ QRstr::set($frame, 0, 7, $setPattern);
+ QRstr::set($frame, $width-8, 7, $setPattern);
+ QRstr::set($frame, 0, $width - 8, $setPattern);
+
+ // Format info
+ $setPattern = str_repeat("\x84", 9);
+ QRstr::set($frame, 0, 8, $setPattern);
+ QRstr::set($frame, $width - 8, 8, $setPattern, 8);
+
+ $yOffset = $width - 8;
+
+ for($y=0; $y<8; $y++,$yOffset++) {
+ $frame[$y][8] = "\x84";
+ $frame[$yOffset][8] = "\x84";
+ }
+
+ // Timing pattern
+
+ for($i=1; $i<$width-15; $i++) {
+ $frame[6][7+$i] = chr(0x90 | ($i & 1));
+ $frame[7+$i][6] = chr(0x90 | ($i & 1));
+ }
+
+ // Alignment pattern
+ self::putAlignmentPattern($version, $frame, $width);
+
+ // Version information
+ if($version >= 7) {
+ $vinf = self::getVersionPattern($version);
+
+ $v = $vinf;
+
+ for($x=0; $x<6; $x++) {
+ for($y=0; $y<3; $y++) {
+ $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
+ $v = $v >> 1;
+ }
+ }
+
+ $v = $vinf;
+ for($y=0; $y<6; $y++) {
+ for($x=0; $x<3; $x++) {
+ $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
+ $v = $v >> 1;
+ }
+ }
+ }
+
+ // and a little bit...
+ $frame[$width - 8][8] = "\x81";
+
+ return $frame;
+ }
+
+ //----------------------------------------------------------------------
+ public static function debug($frame, $binary_mode = false)
+ {
+ if ($binary_mode) {
+
+ foreach ($frame as &$frameLine) {
+ $frameLine = join('<span class="m"> </span>', explode('0', $frameLine));
+ $frameLine = join('██', explode('1', $frameLine));
+ }
+
+ ?>
+ <style>
+ .m { background-color: white; }
+ </style>
+ <?php
+ echo '<pre><tt><br/ ><br/ ><br/ > ';
+ echo join("<br/ > ", $frame);
+ echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >';
+
+ } else {
+
+ foreach ($frame as &$frameLine) {
+ $frameLine = join('<span class="m"> </span>', explode("\xc0", $frameLine));
+ $frameLine = join('<span class="m">▒</span>', explode("\xc1", $frameLine));
+ $frameLine = join('<span class="p"> </span>', explode("\xa0", $frameLine));
+ $frameLine = join('<span class="p">▒</span>', explode("\xa1", $frameLine));
+ $frameLine = join('<span class="s">◇</span>', explode("\x84", $frameLine)); //format 0
+ $frameLine = join('<span class="s">◆</span>', explode("\x85", $frameLine)); //format 1
+ $frameLine = join('<span class="x">☢</span>', explode("\x81", $frameLine)); //special bit
+ $frameLine = join('<span class="c"> </span>', explode("\x90", $frameLine)); //clock 0
+ $frameLine = join('<span class="c">◷</span>', explode("\x91", $frameLine)); //clock 1
+ $frameLine = join('<span class="f"> </span>', explode("\x88", $frameLine)); //version
+ $frameLine = join('<span class="f">▒</span>', explode("\x89", $frameLine)); //version
+ $frameLine = join('♦', explode("\x01", $frameLine));
+ $frameLine = join('⋅', explode("\0", $frameLine));
+ }
+
+ ?>
+ <style>
+ .p { background-color: yellow; }
+ .m { background-color: #00FF00; }
+ .s { background-color: #FF0000; }
+ .c { background-color: aqua; }
+ .x { background-color: pink; }
+ .f { background-color: gold; }
+ </style>
+ <?php
+ echo "<pre><tt>";
+ echo join("<br/ >", $frame);
+ echo "</tt></pre>";
+
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public static function serial($frame)
+ {
+ return gzcompress(join("\n", $frame), 9);
+ }
+
+ //----------------------------------------------------------------------
+ public static function unserial($code)
+ {
+ return explode("\n", gzuncompress($code));
+ }
+
+ //----------------------------------------------------------------------
+ public static function newFrame($version)
+ {
+ if($version < 1 || $version > QRSPEC_VERSION_MAX)
+ return null;
+
+ if(!isset(self::$frames[$version])) {
+
+ $fileName = QR_CACHE_DIR.'frame_'.$version.'.dat';
+
+ if (QR_CACHEABLE) {
+ if (file_exists($fileName)) {
+ self::$frames[$version] = self::unserial(file_get_contents($fileName));
+ } else {
+ self::$frames[$version] = self::createFrame($version);
+ file_put_contents($fileName, self::serial(self::$frames[$version]));
+ }
+ } else {
+ self::$frames[$version] = self::createFrame($version);
+ }
+ }
+
+ if(is_null(self::$frames[$version]))
+ return null;
+
+ return self::$frames[$version];
+ }
+
+ //----------------------------------------------------------------------
+ public static function rsBlockNum($spec) { return $spec[0] + $spec[3]; }
+ public static function rsBlockNum1($spec) { return $spec[0]; }
+ public static function rsDataCodes1($spec) { return $spec[1]; }
+ public static function rsEccCodes1($spec) { return $spec[2]; }
+ public static function rsBlockNum2($spec) { return $spec[3]; }
+ public static function rsDataCodes2($spec) { return $spec[4]; }
+ public static function rsEccCodes2($spec) { return $spec[2]; }
+ public static function rsDataLength($spec) { return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]); }
+ public static function rsEccLength($spec) { return ($spec[0] + $spec[3]) * $spec[2]; }
+
+ } + + + +//---- qrimage.php ----------------------------- + + + +
+/*
+ * PHP QR Code encoder
+ *
+ * Image output of code using GD2
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ define('QR_IMAGE', true);
+
+ class QRimage {
+
+ //----------------------------------------------------------------------
+ public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE)
+ {
+ $image = self::image($frame, $pixelPerPoint, $outerFrame);
+
+ if ($filename === false) {
+ Header("Content-type: image/png");
+ ImagePng($image);
+ } else {
+ if($saveandprint===TRUE){
+ ImagePng($image, $filename);
+ header("Content-type: image/png");
+ ImagePng($image);
+ }else{
+ ImagePng($image, $filename);
+ }
+ }
+
+ ImageDestroy($image);
+ }
+
+ //----------------------------------------------------------------------
+ public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85)
+ {
+ $image = self::image($frame, $pixelPerPoint, $outerFrame);
+
+ if ($filename === false) {
+ Header("Content-type: image/jpeg");
+ ImageJpeg($image, null, $q);
+ } else {
+ ImageJpeg($image, $filename, $q);
+ }
+
+ ImageDestroy($image);
+ }
+
+ //----------------------------------------------------------------------
+ private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4)
+ {
+ $h = count($frame);
+ $w = strlen($frame[0]);
+
+ $imgW = $w + 2*$outerFrame;
+ $imgH = $h + 2*$outerFrame;
+
+ $base_image =ImageCreate($imgW, $imgH);
+
+ $col[0] = ImageColorAllocate($base_image,255,255,255);
+ $col[1] = ImageColorAllocate($base_image,0,0,0);
+
+ imagefill($base_image, 0, 0, $col[0]);
+
+ for($y=0; $y<$h; $y++) {
+ for($x=0; $x<$w; $x++) {
+ if ($frame[$y][$x] == '1') {
+ ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]);
+ }
+ }
+ }
+
+ $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);
+ ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);
+ ImageDestroy($base_image);
+
+ return $target_image;
+ }
+ } + + + +//---- qrinput.php ----------------------------- + + + +
+/*
+ * PHP QR Code encoder
+ *
+ * Input encoding class
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ define('STRUCTURE_HEADER_BITS', 20);
+ define('MAX_STRUCTURED_SYMBOLS', 16);
+
+ class QRinputItem {
+
+ public $mode;
+ public $size;
+ public $data;
+ public $bstream;
+
+ public function __construct($mode, $size, $data, $bstream = null)
+ {
+ $setData = array_slice($data, 0, $size);
+
+ if (count($setData) < $size) {
+ $setData = array_merge($setData, array_fill(0,$size-count($setData),0));
+ }
+
+ if(!QRinput::check($mode, $size, $setData)) {
+ throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData));
+ return null;
+ }
+
+ $this->mode = $mode;
+ $this->size = $size;
+ $this->data = $setData;
+ $this->bstream = $bstream;
+ }
+
+ //----------------------------------------------------------------------
+ public function encodeModeNum($version)
+ {
+ try {
+
+ $words = (int)($this->size / 3);
+ $bs = new QRbitstream();
+
+ $val = 0x1;
+ $bs->appendNum(4, $val);
+ $bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size);
+
+ for($i=0; $i<$words; $i++) {
+ $val = (ord($this->data[$i*3 ]) - ord('0')) * 100;
+ $val += (ord($this->data[$i*3+1]) - ord('0')) * 10;
+ $val += (ord($this->data[$i*3+2]) - ord('0'));
+ $bs->appendNum(10, $val);
+ }
+
+ if($this->size - $words * 3 == 1) {
+ $val = ord($this->data[$words*3]) - ord('0');
+ $bs->appendNum(4, $val);
+ } else if($this->size - $words * 3 == 2) {
+ $val = (ord($this->data[$words*3 ]) - ord('0')) * 10;
+ $val += (ord($this->data[$words*3+1]) - ord('0'));
+ $bs->appendNum(7, $val);
+ }
+
+ $this->bstream = $bs;
+ return 0;
+
+ } catch (Exception $e) {
+ return -1;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public function encodeModeAn($version)
+ {
+ try {
+ $words = (int)($this->size / 2);
+ $bs = new QRbitstream();
+
+ $bs->appendNum(4, 0x02);
+ $bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size);
+
+ for($i=0; $i<$words; $i++) {
+ $val = (int)QRinput::lookAnTable(ord($this->data[$i*2 ])) * 45;
+ $val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1]));
+
+ $bs->appendNum(11, $val);
+ }
+
+ if($this->size & 1) {
+ $val = QRinput::lookAnTable(ord($this->data[$words * 2]));
+ $bs->appendNum(6, $val);
+ }
+
+ $this->bstream = $bs;
+ return 0;
+
+ } catch (Exception $e) {
+ return -1;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public function encodeMode8($version)
+ {
+ try {
+ $bs = new QRbitstream();
+
+ $bs->appendNum(4, 0x4);
+ $bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size);
+
+ for($i=0; $i<$this->size; $i++) {
+ $bs->appendNum(8, ord($this->data[$i]));
+ }
+
+ $this->bstream = $bs;
+ return 0;
+
+ } catch (Exception $e) {
+ return -1;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public function encodeModeKanji($version)
+ {
+ try {
+
+ $bs = new QRbitrtream();
+
+ $bs->appendNum(4, 0x8);
+ $bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2));
+
+ for($i=0; $i<$this->size; $i+=2) {
+ $val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]);
+ if($val <= 0x9ffc) {
+ $val -= 0x8140;
+ } else {
+ $val -= 0xc140;
+ }
+
+ $h = ($val >> 8) * 0xc0;
+ $val = ($val & 0xff) + $h;
+
+ $bs->appendNum(13, $val);
+ }
+
+ $this->bstream = $bs;
+ return 0;
+
+ } catch (Exception $e) {
+ return -1;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public function encodeModeStructure()
+ {
+ try {
+ $bs = new QRbitstream();
+
+ $bs->appendNum(4, 0x03);
+ $bs->appendNum(4, ord($this->data[1]) - 1);
+ $bs->appendNum(4, ord($this->data[0]) - 1);
+ $bs->appendNum(8, ord($this->data[2]));
+
+ $this->bstream = $bs;
+ return 0;
+
+ } catch (Exception $e) {
+ return -1;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public function estimateBitStreamSizeOfEntry($version)
+ {
+ $bits = 0;
+
+ if($version == 0)
+ $version = 1;
+
+ switch($this->mode) {
+ case QR_MODE_NUM: $bits = QRinput::estimateBitsModeNum($this->size); break;
+ case QR_MODE_AN: $bits = QRinput::estimateBitsModeAn($this->size); break;
+ case QR_MODE_8: $bits = QRinput::estimateBitsMode8($this->size); break;
+ case QR_MODE_KANJI: $bits = QRinput::estimateBitsModeKanji($this->size);break;
+ case QR_MODE_STRUCTURE: return STRUCTURE_HEADER_BITS;
+ default:
+ return 0;
+ }
+
+ $l = QRspec::lengthIndicator($this->mode, $version);
+ $m = 1 << $l;
+ $num = (int)(($this->size + $m - 1) / $m);
+
+ $bits += $num * (4 + $l);
+
+ return $bits;
+ }
+
+ //----------------------------------------------------------------------
+ public function encodeBitStream($version)
+ {
+ try {
+
+ unset($this->bstream);
+ $words = QRspec::maximumWords($this->mode, $version);
+
+ if($this->size > $words) {
+
+ $st1 = new QRinputItem($this->mode, $words, $this->data);
+ $st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words));
+
+ $st1->encodeBitStream($version);
+ $st2->encodeBitStream($version);
+
+ $this->bstream = new QRbitstream();
+ $this->bstream->append($st1->bstream);
+ $this->bstream->append($st2->bstream);
+
+ unset($st1);
+ unset($st2);
+
+ } else {
+
+ $ret = 0;
+
+ switch($this->mode) {
+ case QR_MODE_NUM: $ret = $this->encodeModeNum($version); break;
+ case QR_MODE_AN: $ret = $this->encodeModeAn($version); break;
+ case QR_MODE_8: $ret = $this->encodeMode8($version); break;
+ case QR_MODE_KANJI: $ret = $this->encodeModeKanji($version);break;
+ case QR_MODE_STRUCTURE: $ret = $this->encodeModeStructure(); break;
+
+ default:
+ break;
+ }
+
+ if($ret < 0)
+ return -1;
+ }
+
+ return $this->bstream->size();
+
+ } catch (Exception $e) {
+ return -1;
+ }
+ }
+ };
+
+ //##########################################################################
+
+ class QRinput {
+
+ public $items;
+
+ private $version;
+ private $level;
+
+ //----------------------------------------------------------------------
+ public function __construct($version = 0, $level = QR_ECLEVEL_L)
+ {
+ if ($version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) {
+ throw new Exception('Invalid version no');
+ return NULL;
+ }
+
+ $this->version = $version;
+ $this->level = $level;
+ }
+
+ //----------------------------------------------------------------------
+ public function getVersion()
+ {
+ return $this->version;
+ }
+
+ //----------------------------------------------------------------------
+ public function setVersion($version)
+ {
+ if($version < 0 || $version > QRSPEC_VERSION_MAX) {
+ throw new Exception('Invalid version no');
+ return -1;
+ }
+
+ $this->version = $version;
+
+ return 0;
+ }
+
+ //----------------------------------------------------------------------
+ public function getErrorCorrectionLevel()
+ {
+ return $this->level;
+ }
+
+ //----------------------------------------------------------------------
+ public function setErrorCorrectionLevel($level)
+ {
+ if($level > QR_ECLEVEL_H) {
+ throw new Exception('Invalid ECLEVEL');
+ return -1;
+ }
+
+ $this->level = $level;
+
+ return 0;
+ }
+
+ //----------------------------------------------------------------------
+ public function appendEntry(QRinputItem $entry)
+ {
+ $this->items[] = $entry;
+ }
+
+ //----------------------------------------------------------------------
+ public function append($mode, $size, $data)
+ {
+ try {
+ $entry = new QRinputItem($mode, $size, $data);
+ $this->items[] = $entry;
+ return 0;
+ } catch (Exception $e) {
+ return -1;
+ }
+ }
+
+ //----------------------------------------------------------------------
+
+ public function insertStructuredAppendHeader($size, $index, $parity)
+ {
+ if( $size > MAX_STRUCTURED_SYMBOLS ) {
+ throw new Exception('insertStructuredAppendHeader wrong size');
+ }
+
+ if( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) {
+ throw new Exception('insertStructuredAppendHeader wrong index');
+ }
+
+ $buf = array($size, $index, $parity);
+
+ try {
+ $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf);
+ array_unshift($this->items, $entry);
+ return 0;
+ } catch (Exception $e) {
+ return -1;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public function calcParity()
+ {
+ $parity = 0;
+
+ foreach($this->items as $item) {
+ if($item->mode != QR_MODE_STRUCTURE) {
+ for($i=$item->size-1; $i>=0; $i--) {
+ $parity ^= $item->data[$i];
+ }
+ }
+ }
+
+ return $parity;
+ }
+
+ //----------------------------------------------------------------------
+ public static function checkModeNum($size, $data)
+ {
+ for($i=0; $i<$size; $i++) {
+ if((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ //----------------------------------------------------------------------
+ public static function estimateBitsModeNum($size)
+ {
+ $w = (int)$size / 3;
+ $bits = $w * 10;
+
+ switch($size - $w * 3) {
+ case 1:
+ $bits += 4;
+ break;
+ case 2:
+ $bits += 7;
+ break;
+ default:
+ break;
+ }
+
+ return $bits;
+ }
+
+ //----------------------------------------------------------------------
+ public static $anTable = array(
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ );
+
+ //----------------------------------------------------------------------
+ public static function lookAnTable($c)
+ {
+ return (($c > 127)?-1:self::$anTable[$c]);
+ }
+
+ //----------------------------------------------------------------------
+ public static function checkModeAn($size, $data)
+ {
+ for($i=0; $i<$size; $i++) {
+ if (self::lookAnTable(ord($data[$i])) == -1) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ //----------------------------------------------------------------------
+ public static function estimateBitsModeAn($size)
+ {
+ $w = (int)($size / 2);
+ $bits = $w * 11;
+
+ if($size & 1) {
+ $bits += 6;
+ }
+
+ return $bits;
+ }
+
+ //----------------------------------------------------------------------
+ public static function estimateBitsMode8($size)
+ {
+ return $size * 8;
+ }
+
+ //----------------------------------------------------------------------
+ public function estimateBitsModeKanji($size)
+ {
+ return (int)(($size / 2) * 13);
+ }
+
+ //----------------------------------------------------------------------
+ public static function checkModeKanji($size, $data)
+ {
+ if($size & 1)
+ return false;
+
+ for($i=0; $i<$size; $i+=2) {
+ $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
+ if( $val < 0x8140
+ || ($val > 0x9ffc && $val < 0xe040)
+ || $val > 0xebbf) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /***********************************************************************
+ * Validation
+ **********************************************************************/
+
+ public static function check($mode, $size, $data)
+ {
+ if($size <= 0)
+ return false;
+
+ switch($mode) {
+ case QR_MODE_NUM: return self::checkModeNum($size, $data); break;
+ case QR_MODE_AN: return self::checkModeAn($size, $data); break;
+ case QR_MODE_KANJI: return self::checkModeKanji($size, $data); break;
+ case QR_MODE_8: return true; break;
+ case QR_MODE_STRUCTURE: return true; break;
+
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+
+ //----------------------------------------------------------------------
+ public function estimateBitStreamSize($version)
+ {
+ $bits = 0;
+
+ foreach($this->items as $item) {
+ $bits += $item->estimateBitStreamSizeOfEntry($version);
+ }
+
+ return $bits;
+ }
+
+ //----------------------------------------------------------------------
+ public function estimateVersion()
+ {
+ $version = 0;
+ $prev = 0;
+ do {
+ $prev = $version;
+ $bits = $this->estimateBitStreamSize($prev);
+ $version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
+ if ($version < 0) {
+ return -1;
+ }
+ } while ($version > $prev);
+
+ return $version;
+ }
+
+ //----------------------------------------------------------------------
+ public static function lengthOfCode($mode, $version, $bits)
+ {
+ $payload = $bits - 4 - QRspec::lengthIndicator($mode, $version);
+ switch($mode) {
+ case QR_MODE_NUM:
+ $chunks = (int)($payload / 10);
+ $remain = $payload - $chunks * 10;
+ $size = $chunks * 3;
+ if($remain >= 7) {
+ $size += 2;
+ } else if($remain >= 4) {
+ $size += 1;
+ }
+ break;
+ case QR_MODE_AN:
+ $chunks = (int)($payload / 11);
+ $remain = $payload - $chunks * 11;
+ $size = $chunks * 2;
+ if($remain >= 6)
+ $size++;
+ break;
+ case QR_MODE_8:
+ $size = (int)($payload / 8);
+ break;
+ case QR_MODE_KANJI:
+ $size = (int)(($payload / 13) * 2);
+ break;
+ case QR_MODE_STRUCTURE:
+ $size = (int)($payload / 8);
+ break;
+ default:
+ $size = 0;
+ break;
+ }
+
+ $maxsize = QRspec::maximumWords($mode, $version);
+ if($size < 0) $size = 0;
+ if($size > $maxsize) $size = $maxsize;
+
+ return $size;
+ }
+
+ //----------------------------------------------------------------------
+ public function createBitStream()
+ {
+ $total = 0;
+
+ foreach($this->items as $item) {
+ $bits = $item->encodeBitStream($this->version);
+
+ if($bits < 0)
+ return -1;
+
+ $total += $bits;
+ }
+
+ return $total;
+ }
+
+ //----------------------------------------------------------------------
+ public function convertData()
+ {
+ $ver = $this->estimateVersion();
+ if($ver > $this->getVersion()) {
+ $this->setVersion($ver);
+ }
+
+ for(;;) {
+ $bits = $this->createBitStream();
+
+ if($bits < 0)
+ return -1;
+
+ $ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
+ if($ver < 0) {
+ throw new Exception('WRONG VERSION');
+ return -1;
+ } else if($ver > $this->getVersion()) {
+ $this->setVersion($ver);
+ } else {
+ break;
+ }
+ }
+
+ return 0;
+ }
+
+ //----------------------------------------------------------------------
+ public function appendPaddingBit(&$bstream)
+ {
+ $bits = $bstream->size();
+ $maxwords = QRspec::getDataLength($this->version, $this->level);
+ $maxbits = $maxwords * 8;
+
+ if ($maxbits == $bits) {
+ return 0;
+ }
+
+ if ($maxbits - $bits < 5) {
+ return $bstream->appendNum($maxbits - $bits, 0);
+ }
+
+ $bits += 4;
+ $words = (int)(($bits + 7) / 8);
+
+ $padding = new QRbitstream();
+ $ret = $padding->appendNum($words * 8 - $bits + 4, 0);
+
+ if($ret < 0)
+ return $ret;
+
+ $padlen = $maxwords - $words;
+
+ if($padlen > 0) {
+
+ $padbuf = array();
+ for($i=0; $i<$padlen; $i++) {
+ $padbuf[$i] = ($i&1)?0x11:0xec;
+ }
+
+ $ret = $padding->appendBytes($padlen, $padbuf);
+
+ if($ret < 0)
+ return $ret;
+
+ }
+
+ $ret = $bstream->append($padding);
+
+ return $ret;
+ }
+
+ //----------------------------------------------------------------------
+ public function mergeBitStream()
+ {
+ if($this->convertData() < 0) {
+ return null;
+ }
+
+ $bstream = new QRbitstream();
+
+ foreach($this->items as $item) {
+ $ret = $bstream->append($item->bstream);
+ if($ret < 0) {
+ return null;
+ }
+ }
+
+ return $bstream;
+ }
+
+ //----------------------------------------------------------------------
+ public function getBitStream()
+ {
+
+ $bstream = $this->mergeBitStream();
+
+ if($bstream == null) {
+ return null;
+ }
+
+ $ret = $this->appendPaddingBit($bstream);
+ if($ret < 0) {
+ return null;
+ }
+
+ return $bstream;
+ }
+
+ //----------------------------------------------------------------------
+ public function getByteStream()
+ {
+ $bstream = $this->getBitStream();
+ if($bstream == null) {
+ return null;
+ }
+
+ return $bstream->toByte();
+ }
+ }
+
+
+ + + + +//---- qrbitstream.php ----------------------------- + + + +
+/*
+ * PHP QR Code encoder
+ *
+ * Bitstream class
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ class QRbitstream {
+
+ public $data = array();
+
+ //----------------------------------------------------------------------
+ public function size()
+ {
+ return count($this->data);
+ }
+
+ //----------------------------------------------------------------------
+ public function allocate($setLength)
+ {
+ $this->data = array_fill(0, $setLength, 0);
+ return 0;
+ }
+
+ //----------------------------------------------------------------------
+ public static function newFromNum($bits, $num)
+ {
+ $bstream = new QRbitstream();
+ $bstream->allocate($bits);
+
+ $mask = 1 << ($bits - 1);
+ for($i=0; $i<$bits; $i++) {
+ if($num & $mask) {
+ $bstream->data[$i] = 1;
+ } else {
+ $bstream->data[$i] = 0;
+ }
+ $mask = $mask >> 1;
+ }
+
+ return $bstream;
+ }
+
+ //----------------------------------------------------------------------
+ public static function newFromBytes($size, $data)
+ {
+ $bstream = new QRbitstream();
+ $bstream->allocate($size * 8);
+ $p=0;
+
+ for($i=0; $i<$size; $i++) {
+ $mask = 0x80;
+ for($j=0; $j<8; $j++) {
+ if($data[$i] & $mask) {
+ $bstream->data[$p] = 1;
+ } else {
+ $bstream->data[$p] = 0;
+ }
+ $p++;
+ $mask = $mask >> 1;
+ }
+ }
+
+ return $bstream;
+ }
+
+ //----------------------------------------------------------------------
+ public function append(QRbitstream $arg)
+ {
+ if (is_null($arg)) {
+ return -1;
+ }
+
+ if($arg->size() == 0) {
+ return 0;
+ }
+
+ if($this->size() == 0) {
+ $this->data = $arg->data;
+ return 0;
+ }
+
+ $this->data = array_values(array_merge($this->data, $arg->data));
+
+ return 0;
+ }
+
+ //----------------------------------------------------------------------
+ public function appendNum($bits, $num)
+ {
+ if ($bits == 0)
+ return 0;
+
+ $b = QRbitstream::newFromNum($bits, $num);
+
+ if(is_null($b))
+ return -1;
+
+ $ret = $this->append($b);
+ unset($b);
+
+ return $ret;
+ }
+
+ //----------------------------------------------------------------------
+ public function appendBytes($size, $data)
+ {
+ if ($size == 0)
+ return 0;
+
+ $b = QRbitstream::newFromBytes($size, $data);
+
+ if(is_null($b))
+ return -1;
+
+ $ret = $this->append($b);
+ unset($b);
+
+ return $ret;
+ }
+
+ //----------------------------------------------------------------------
+ public function toByte()
+ {
+
+ $size = $this->size();
+
+ if($size == 0) {
+ return array();
+ }
+
+ $data = array_fill(0, (int)(($size + 7) / 8), 0);
+ $bytes = (int)($size / 8);
+
+ $p = 0;
+
+ for($i=0; $i<$bytes; $i++) {
+ $v = 0;
+ for($j=0; $j<8; $j++) {
+ $v = $v << 1;
+ $v |= $this->data[$p];
+ $p++;
+ }
+ $data[$i] = $v;
+ }
+
+ if($size & 7) {
+ $v = 0;
+ for($j=0; $j<($size & 7); $j++) {
+ $v = $v << 1;
+ $v |= $this->data[$p];
+ $p++;
+ }
+ $data[$bytes] = $v;
+ }
+
+ return $data;
+ }
+
+ }
+ + + + +//---- qrsplit.php ----------------------------- + + + +
+/*
+ * PHP QR Code encoder
+ *
+ * Input splitting classes
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * The following data / specifications are taken from
+ * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
+ * or
+ * "Automatic identification and data capture techniques --
+ * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+ class QRsplit {
+
+ public $dataStr = '';
+ public $input;
+ public $modeHint;
+
+ //----------------------------------------------------------------------
+ public function __construct($dataStr, $input, $modeHint)
+ {
+ $this->dataStr = $dataStr;
+ $this->input = $input;
+ $this->modeHint = $modeHint;
+ }
+
+ //----------------------------------------------------------------------
+ public static function isdigitat($str, $pos)
+ {
+ if ($pos >= strlen($str))
+ return false;
+
+ return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
+ }
+
+ //----------------------------------------------------------------------
+ public static function isalnumat($str, $pos)
+ {
+ if ($pos >= strlen($str))
+ return false;
+
+ return (QRinput::lookAnTable(ord($str[$pos])) >= 0);
+ }
+
+ //----------------------------------------------------------------------
+ public function identifyMode($pos)
+ {
+ if ($pos >= strlen($this->dataStr))
+ return QR_MODE_NUL;
+
+ $c = $this->dataStr[$pos];
+
+ if(self::isdigitat($this->dataStr, $pos)) {
+ return QR_MODE_NUM;
+ } else if(self::isalnumat($this->dataStr, $pos)) {
+ return QR_MODE_AN;
+ } else if($this->modeHint == QR_MODE_KANJI) {
+
+ if ($pos+1 < strlen($this->dataStr))
+ {
+ $d = $this->dataStr[$pos+1];
+ $word = (ord($c) << 8) | ord($d);
+ if(($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) {
+ return QR_MODE_KANJI;
+ }
+ }
+ }
+
+ return QR_MODE_8;
+ }
+
+ //----------------------------------------------------------------------
+ public function eatNum()
+ {
+ $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
+
+ $p = 0;
+ while(self::isdigitat($this->dataStr, $p)) {
+ $p++;
+ }
+
+ $run = $p;
+ $mode = $this->identifyMode($p);
+
+ if($mode == QR_MODE_8) {
+ $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
+ + QRinput::estimateBitsMode8(1) // + 4 + l8
+ - QRinput::estimateBitsMode8($run + 1); // - 4 - l8
+ if($dif > 0) {
+ return $this->eat8();
+ }
+ }
+ if($mode == QR_MODE_AN) {
+ $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
+ + QRinput::estimateBitsModeAn(1) // + 4 + la
+ - QRinput::estimateBitsModeAn($run + 1);// - 4 - la
+ if($dif > 0) {
+ return $this->eatAn();
+ }
+ }
+
+ $ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr));
+ if($ret < 0)
+ return -1;
+
+ return $run;
+ }
+
+ //----------------------------------------------------------------------
+ public function eatAn()
+ {
+ $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
+ $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
+
+ $p = 0;
+
+ while(self::isalnumat($this->dataStr, $p)) {
+ if(self::isdigitat($this->dataStr, $p)) {
+ $q = $p;
+ while(self::isdigitat($this->dataStr, $q)) {
+ $q++;
+ }
+
+ $dif = QRinput::estimateBitsModeAn($p) // + 4 + la
+ + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
+ - QRinput::estimateBitsModeAn($q); // - 4 - la
+
+ if($dif < 0) {
+ break;
+ } else {
+ $p = $q;
+ }
+ } else {
+ $p++;
+ }
+ }
+
+ $run = $p;
+
+ if(!self::isalnumat($this->dataStr, $p)) {
+ $dif = QRinput::estimateBitsModeAn($run) + 4 + $la
+ + QRinput::estimateBitsMode8(1) // + 4 + l8
+ - QRinput::estimateBitsMode8($run + 1); // - 4 - l8
+ if($dif > 0) {
+ return $this->eat8();
+ }
+ }
+
+ $ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr));
+ if($ret < 0)
+ return -1;
+
+ return $run;
+ }
+
+ //----------------------------------------------------------------------
+ public function eatKanji()
+ {
+ $p = 0;
+
+ while($this->identifyMode($p) == QR_MODE_KANJI) {
+ $p += 2;
+ }
+
+ $ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr));
+ if($ret < 0)
+ return -1;
+
+ return $run;
+ }
+
+ //----------------------------------------------------------------------
+ public function eat8()
+ {
+ $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
+ $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
+
+ $p = 1;
+ $dataStrLen = strlen($this->dataStr);
+
+ while($p < $dataStrLen) {
+
+ $mode = $this->identifyMode($p);
+ if($mode == QR_MODE_KANJI) {
+ break;
+ }
+ if($mode == QR_MODE_NUM) {
+ $q = $p;
+ while(self::isdigitat($this->dataStr, $q)) {
+ $q++;
+ }
+ $dif = QRinput::estimateBitsMode8($p) // + 4 + l8
+ + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
+ - QRinput::estimateBitsMode8($q); // - 4 - l8
+ if($dif < 0) {
+ break;
+ } else {
+ $p = $q;
+ }
+ } else if($mode == QR_MODE_AN) {
+ $q = $p;
+ while(self::isalnumat($this->dataStr, $q)) {
+ $q++;
+ }
+ $dif = QRinput::estimateBitsMode8($p) // + 4 + l8
+ + QRinput::estimateBitsModeAn($q - $p) + 4 + $la
+ - QRinput::estimateBitsMode8($q); // - 4 - l8
+ if($dif < 0) {
+ break;
+ } else {
+ $p = $q;
+ }
+ } else {
+ $p++;
+ }
+ }
+
+ $run = $p;
+ $ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr));
+
+ if($ret < 0)
+ return -1;
+
+ return $run;
+ }
+
+ //----------------------------------------------------------------------
+ public function splitString()
+ {
+ while (strlen($this->dataStr) > 0)
+ {
+ if($this->dataStr == '')
+ return 0;
+
+ $mode = $this->identifyMode(0);
+
+ switch ($mode) {
+ case QR_MODE_NUM: $length = $this->eatNum(); break;
+ case QR_MODE_AN: $length = $this->eatAn(); break;
+ case QR_MODE_KANJI:
+ if ($hint == QR_MODE_KANJI)
+ $length = $this->eatKanji();
+ else $length = $this->eat8();
+ break;
+ default: $length = $this->eat8(); break;
+
+ }
+
+ if($length == 0) return 0;
+ if($length < 0) return -1;
+
+ $this->dataStr = substr($this->dataStr, $length);
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public function toUpper()
+ {
+ $stringLen = strlen($this->dataStr);
+ $p = 0;
+
+ while ($p<$stringLen) {
+ $mode = self::identifyMode(substr($this->dataStr, $p), $this->modeHint);
+ if($mode == QR_MODE_KANJI) {
+ $p += 2;
+ } else {
+ if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) {
+ $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
+ }
+ $p++;
+ }
+ }
+
+ return $this->dataStr;
+ }
+
+ //----------------------------------------------------------------------
+ public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true)
+ {
+ if(is_null($string) || $string == '\0' || $string == '') {
+ throw new Exception('empty string!!!');
+ }
+
+ $split = new QRsplit($string, $input, $modeHint);
+
+ if(!$casesensitive)
+ $split->toUpper();
+
+ return $split->splitString();
+ }
+ } + + + +//---- qrrscode.php ----------------------------- + + + +
+/*
+ * PHP QR Code encoder
+ *
+ * Reed-Solomon error correction support
+ *
+ * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
+ * (libfec is released under the GNU Lesser General Public License.)
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ class QRrsItem {
+
+ public $mm; // Bits per symbol
+ public $nn; // Symbols per block (= (1<<mm)-1)
+ public $alpha_to = array(); // log lookup table
+ public $index_of = array(); // Antilog lookup table
+ public $genpoly = array(); // Generator polynomial
+ public $nroots; // Number of generator roots = number of parity symbols
+ public $fcr; // First consecutive root, index form
+ public $prim; // Primitive element, index form
+ public $iprim; // prim-th root of 1, index form
+ public $pad; // Padding bytes in shortened block
+ public $gfpoly;
+
+ //----------------------------------------------------------------------
+ public function modnn($x)
+ {
+ while ($x >= $this->nn) {
+ $x -= $this->nn;
+ $x = ($x >> $this->mm) + ($x & $this->nn);
+ }
+
+ return $x;
+ }
+
+ //----------------------------------------------------------------------
+ public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
+ {
+ // Common code for intializing a Reed-Solomon control block (char or int symbols)
+ // Copyright 2004 Phil Karn, KA9Q
+ // May be used under the terms of the GNU Lesser General Public License (LGPL)
+
+ $rs = null;
+
+ // Check parameter ranges
+ if($symsize < 0 || $symsize > 8) return $rs;
+ if($fcr < 0 || $fcr >= (1<<$symsize)) return $rs;
+ if($prim <= 0 || $prim >= (1<<$symsize)) return $rs;
+ if($nroots < 0 || $nroots >= (1<<$symsize)) return $rs; // Can't have more roots than symbol values!
+ if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; // Too much padding
+
+ $rs = new QRrsItem();
+ $rs->mm = $symsize;
+ $rs->nn = (1<<$symsize)-1;
+ $rs->pad = $pad;
+
+ $rs->alpha_to = array_fill(0, $rs->nn+1, 0);
+ $rs->index_of = array_fill(0, $rs->nn+1, 0);
+
+ // PHP style macro replacement ;)
+ $NN =& $rs->nn;
+ $A0 =& $NN;
+
+ // Generate Galois field lookup tables
+ $rs->index_of[0] = $A0; // log(zero) = -inf
+ $rs->alpha_to[$A0] = 0; // alpha**-inf = 0
+ $sr = 1;
+
+ for($i=0; $i<$rs->nn; $i++) {
+ $rs->index_of[$sr] = $i;
+ $rs->alpha_to[$i] = $sr;
+ $sr <<= 1;
+ if($sr & (1<<$symsize)) {
+ $sr ^= $gfpoly;
+ }
+ $sr &= $rs->nn;
+ }
+
+ if($sr != 1){
+ // field generator polynomial is not primitive!
+ $rs = NULL;
+ return $rs;
+ }
+
+ /* Form RS code generator polynomial from its roots */
+ $rs->genpoly = array_fill(0, $nroots+1, 0);
+
+ $rs->fcr = $fcr;
+ $rs->prim = $prim;
+ $rs->nroots = $nroots;
+ $rs->gfpoly = $gfpoly;
+
+ /* Find prim-th root of 1, used in decoding */
+ for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn)
+ ; // intentional empty-body loop!
+
+ $rs->iprim = (int)($iprim / $prim);
+ $rs->genpoly[0] = 1;
+
+ for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
+ $rs->genpoly[$i+1] = 1;
+
+ // Multiply rs->genpoly[] by @**(root + x)
+ for ($j = $i; $j > 0; $j--) {
+ if ($rs->genpoly[$j] != 0) {
+ $rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)];
+ } else {
+ $rs->genpoly[$j] = $rs->genpoly[$j-1];
+ }
+ }
+ // rs->genpoly[0] can never be zero
+ $rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)];
+ }
+
+ // convert rs->genpoly[] to index form for quicker encoding
+ for ($i = 0; $i <= $nroots; $i++)
+ $rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]];
+
+ return $rs;
+ }
+
+ //----------------------------------------------------------------------
+ public function encode_rs_char($data, &$parity)
+ {
+ $MM =& $this->mm;
+ $NN =& $this->nn;
+ $ALPHA_TO =& $this->alpha_to;
+ $INDEX_OF =& $this->index_of;
+ $GENPOLY =& $this->genpoly;
+ $NROOTS =& $this->nroots;
+ $FCR =& $this->fcr;
+ $PRIM =& $this->prim;
+ $IPRIM =& $this->iprim;
+ $PAD =& $this->pad;
+ $A0 =& $NN;
+
+ $parity = array_fill(0, $NROOTS, 0);
+
+ for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) {
+
+ $feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
+ if($feedback != $A0) {
+ // feedback term is non-zero
+
+ // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
+ // always be for the polynomials constructed by init_rs()
+ $feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback);
+
+ for($j=1;$j<$NROOTS;$j++) {
+ $parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])];
+ }
+ }
+
+ // Shift
+ array_shift($parity);
+ if($feedback != $A0) {
+ array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]);
+ } else {
+ array_push($parity, 0);
+ }
+ }
+ }
+ }
+
+ //##########################################################################
+
+ class QRrs {
+
+ public static $items = array();
+
+ //----------------------------------------------------------------------
+ public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
+ {
+ foreach(self::$items as $rs) {
+ if($rs->pad != $pad) continue;
+ if($rs->nroots != $nroots) continue;
+ if($rs->mm != $symsize) continue;
+ if($rs->gfpoly != $gfpoly) continue;
+ if($rs->fcr != $fcr) continue;
+ if($rs->prim != $prim) continue;
+
+ return $rs;
+ }
+
+ $rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
+ array_unshift(self::$items, $rs);
+
+ return $rs;
+ }
+ } + + + +//---- qrmask.php ----------------------------- + + + +
+/*
+ * PHP QR Code encoder
+ *
+ * Masking
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ define('N1', 3);
+ define('N2', 3);
+ define('N3', 40);
+ define('N4', 10);
+
+ class QRmask {
+
+ public $runLength = array();
+
+ //----------------------------------------------------------------------
+ public function __construct()
+ {
+ $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
+ }
+
+ //----------------------------------------------------------------------
+ public function writeFormatInformation($width, &$frame, $mask, $level)
+ {
+ $blacks = 0;
+ $format = QRspec::getFormatInfo($mask, $level);
+
+ for($i=0; $i<8; $i++) {
+ if($format & 1) {
+ $blacks += 2;
+ $v = 0x85;
+ } else {
+ $v = 0x84;
+ }
+
+ $frame[8][$width - 1 - $i] = chr($v);
+ if($i < 6) {
+ $frame[$i][8] = chr($v);
+ } else {
+ $frame[$i + 1][8] = chr($v);
+ }
+ $format = $format >> 1;
+ }
+
+ for($i=0; $i<7; $i++) {
+ if($format & 1) {
+ $blacks += 2;
+ $v = 0x85;
+ } else {
+ $v = 0x84;
+ }
+
+ $frame[$width - 7 + $i][8] = chr($v);
+ if($i == 0) {
+ $frame[8][7] = chr($v);
+ } else {
+ $frame[8][6 - $i] = chr($v);
+ }
+
+ $format = $format >> 1;
+ }
+
+ return $blacks;
+ }
+
+ //----------------------------------------------------------------------
+ public function mask0($x, $y) { return ($x+$y)&1; }
+ public function mask1($x, $y) { return ($y&1); }
+ public function mask2($x, $y) { return ($x%3); }
+ public function mask3($x, $y) { return ($x+$y)%3; }
+ public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; }
+ public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3; }
+ public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1; }
+ public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1; }
+
+ //----------------------------------------------------------------------
+ private function generateMaskNo($maskNo, $width, $frame)
+ {
+ $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
+
+ for($y=0; $y<$width; $y++) {
+ for($x=0; $x<$width; $x++) {
+ if(ord($frame[$y][$x]) & 0x80) {
+ $bitMask[$y][$x] = 0;
+ } else {
+ $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
+ $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
+ }
+
+ }
+ }
+
+ return $bitMask;
+ }
+
+ //----------------------------------------------------------------------
+ public static function serial($bitFrame)
+ {
+ $codeArr = array();
+
+ foreach ($bitFrame as $line)
+ $codeArr[] = join('', $line);
+
+ return gzcompress(join("\n", $codeArr), 9);
+ }
+
+ //----------------------------------------------------------------------
+ public static function unserial($code)
+ {
+ $codeArr = array();
+
+ $codeLines = explode("\n", gzuncompress($code));
+ foreach ($codeLines as $line)
+ $codeArr[] = str_split($line);
+
+ return $codeArr;
+ }
+
+ //----------------------------------------------------------------------
+ public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false)
+ {
+ $b = 0;
+ $bitMask = array();
+
+ $fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat';
+
+ if (QR_CACHEABLE) {
+ if (file_exists($fileName)) {
+ $bitMask = self::unserial(file_get_contents($fileName));
+ } else {
+ $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
+ if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo))
+ mkdir(QR_CACHE_DIR.'mask_'.$maskNo);
+ file_put_contents($fileName, self::serial($bitMask));
+ }
+ } else {
+ $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
+ }
+
+ if ($maskGenOnly)
+ return;
+
+ $d = $s;
+
+ for($y=0; $y<$width; $y++) {
+ for($x=0; $x<$width; $x++) {
+ if($bitMask[$y][$x] == 1) {
+ $d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
+ }
+ $b += (int)(ord($d[$y][$x]) & 1);
+ }
+ }
+
+ return $b;
+ }
+
+ //----------------------------------------------------------------------
+ public function makeMask($width, $frame, $maskNo, $level)
+ {
+ $masked = array_fill(0, $width, str_repeat("\0", $width));
+ $this->makeMaskNo($maskNo, $width, $frame, $masked);
+ $this->writeFormatInformation($width, $masked, $maskNo, $level);
+
+ return $masked;
+ }
+
+ //----------------------------------------------------------------------
+ public function calcN1N3($length)
+ {
+ $demerit = 0;
+
+ for($i=0; $i<$length; $i++) {
+
+ if($this->runLength[$i] >= 5) {
+ $demerit += (N1 + ($this->runLength[$i] - 5));
+ }
+ if($i & 1) {
+ if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) {
+ $fact = (int)($this->runLength[$i] / 3);
+ if(($this->runLength[$i-2] == $fact) &&
+ ($this->runLength[$i-1] == $fact) &&
+ ($this->runLength[$i+1] == $fact) &&
+ ($this->runLength[$i+2] == $fact)) {
+ if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) {
+ $demerit += N3;
+ } else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) {
+ $demerit += N3;
+ }
+ }
+ }
+ }
+ }
+ return $demerit;
+ }
+
+ //----------------------------------------------------------------------
+ public function evaluateSymbol($width, $frame)
+ {
+ $head = 0;
+ $demerit = 0;
+
+ for($y=0; $y<$width; $y++) {
+ $head = 0;
+ $this->runLength[0] = 1;
+
+ $frameY = $frame[$y];
+
+ if ($y>0)
+ $frameYM = $frame[$y-1];
+
+ for($x=0; $x<$width; $x++) {
+ if(($x > 0) && ($y > 0)) {
+ $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
+ $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
+
+ if(($b22 | ($w22 ^ 1))&1) {
+ $demerit += N2;
+ }
+ }
+ if(($x == 0) && (ord($frameY[$x]) & 1)) {
+ $this->runLength[0] = -1;
+ $head = 1;
+ $this->runLength[$head] = 1;
+ } else if($x > 0) {
+ if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
+ $head++;
+ $this->runLength[$head] = 1;
+ } else {
+ $this->runLength[$head]++;
+ }
+ }
+ }
+
+ $demerit += $this->calcN1N3($head+1);
+ }
+
+ for($x=0; $x<$width; $x++) {
+ $head = 0;
+ $this->runLength[0] = 1;
+
+ for($y=0; $y<$width; $y++) {
+ if($y == 0 && (ord($frame[$y][$x]) & 1)) {
+ $this->runLength[0] = -1;
+ $head = 1;
+ $this->runLength[$head] = 1;
+ } else if($y > 0) {
+ if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
+ $head++;
+ $this->runLength[$head] = 1;
+ } else {
+ $this->runLength[$head]++;
+ }
+ }
+ }
+
+ $demerit += $this->calcN1N3($head+1);
+ }
+
+ return $demerit;
+ }
+
+
+ //----------------------------------------------------------------------
+ public function mask($width, $frame, $level)
+ {
+ $minDemerit = PHP_INT_MAX;
+ $bestMaskNum = 0;
+ $bestMask = array();
+
+ $checked_masks = array(0,1,2,3,4,5,6,7);
+
+ if (QR_FIND_FROM_RANDOM !== false) {
+
+ $howManuOut = 8-(QR_FIND_FROM_RANDOM % 9);
+ for ($i = 0; $i < $howManuOut; $i++) {
+ $remPos = rand (0, count($checked_masks)-1);
+ unset($checked_masks[$remPos]);
+ $checked_masks = array_values($checked_masks);
+ }
+
+ }
+
+ $bestMask = $frame;
+
+ foreach($checked_masks as $i) {
+ $mask = array_fill(0, $width, str_repeat("\0", $width));
+
+ $demerit = 0;
+ $blacks = 0;
+ $blacks = $this->makeMaskNo($i, $width, $frame, $mask);
+ $blacks += $this->writeFormatInformation($width, $mask, $i, $level);
+ $blacks = (int)(100 * $blacks / ($width * $width));
+ $demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
+ $demerit += $this->evaluateSymbol($width, $mask);
+
+ if($demerit < $minDemerit) {
+ $minDemerit = $demerit;
+ $bestMask = $mask;
+ $bestMaskNum = $i;
+ }
+ }
+
+ return $bestMask;
+ }
+
+ //----------------------------------------------------------------------
+ }
+ + + + +//---- qrencode.php ----------------------------- + + + +
+/*
+ * PHP QR Code encoder
+ *
+ * Main encoder classes.
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * 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 3 of the License, or 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ class QRrsblock {
+ public $dataLength;
+ public $data = array();
+ public $eccLength;
+ public $ecc = array();
+
+ public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs)
+ {
+ $rs->encode_rs_char($data, $ecc);
+
+ $this->dataLength = $dl;
+ $this->data = $data;
+ $this->eccLength = $el;
+ $this->ecc = $ecc;
+ }
+ };
+
+ //##########################################################################
+
+ class QRrawcode {
+ public $version;
+ public $datacode = array();
+ public $ecccode = array();
+ public $blocks;
+ public $rsblocks = array(); //of RSblock
+ public $count;
+ public $dataLength;
+ public $eccLength;
+ public $b1;
+
+ //----------------------------------------------------------------------
+ public function __construct(QRinput $input)
+ {
+ $spec = array(0,0,0,0,0);
+
+ $this->datacode = $input->getByteStream();
+ if(is_null($this->datacode)) {
+ throw new Exception('null imput string');
+ }
+
+ QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec);
+
+ $this->version = $input->getVersion();
+ $this->b1 = QRspec::rsBlockNum1($spec);
+ $this->dataLength = QRspec::rsDataLength($spec);
+ $this->eccLength = QRspec::rsEccLength($spec);
+ $this->ecccode = array_fill(0, $this->eccLength, 0);
+ $this->blocks = QRspec::rsBlockNum($spec);
+
+ $ret = $this->init($spec);
+ if($ret < 0) {
+ throw new Exception('block alloc error');
+ return null;
+ }
+
+ $this->count = 0;
+ }
+
+ //----------------------------------------------------------------------
+ public function init(array $spec)
+ {
+ $dl = QRspec::rsDataCodes1($spec);
+ $el = QRspec::rsEccCodes1($spec);
+ $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
+
+
+ $blockNo = 0;
+ $dataPos = 0;
+ $eccPos = 0;
+ for($i=0; $i<QRspec::rsBlockNum1($spec); $i++) {
+ $ecc = array_slice($this->ecccode,$eccPos);
+ $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
+ $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
+
+ $dataPos += $dl;
+ $eccPos += $el;
+ $blockNo++;
+ }
+
+ if(QRspec::rsBlockNum2($spec) == 0)
+ return 0;
+
+ $dl = QRspec::rsDataCodes2($spec);
+ $el = QRspec::rsEccCodes2($spec);
+ $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
+
+ if($rs == NULL) return -1;
+
+ for($i=0; $i<QRspec::rsBlockNum2($spec); $i++) {
+ $ecc = array_slice($this->ecccode,$eccPos);
+ $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
+ $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
+
+ $dataPos += $dl;
+ $eccPos += $el;
+ $blockNo++;
+ }
+
+ return 0;
+ }
+
+ //----------------------------------------------------------------------
+ public function getCode()
+ {
+ $ret;
+
+ if($this->count < $this->dataLength) {
+ $row = $this->count % $this->blocks;
+ $col = $this->count / $this->blocks;
+ if($col >= $this->rsblocks[0]->dataLength) {
+ $row += $this->b1;
+ }
+ $ret = $this->rsblocks[$row]->data[$col];
+ } else if($this->count < $this->dataLength + $this->eccLength) {
+ $row = ($this->count - $this->dataLength) % $this->blocks;
+ $col = ($this->count - $this->dataLength) / $this->blocks;
+ $ret = $this->rsblocks[$row]->ecc[$col];
+ } else {
+ return 0;
+ }
+ $this->count++;
+
+ return $ret;
+ }
+ }
+
+ //##########################################################################
+
+ class QRcode {
+
+ public $version;
+ public $width;
+ public $data;
+
+ //----------------------------------------------------------------------
+ public function encodeMask(QRinput $input, $mask)
+ {
+ if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) {
+ throw new Exception('wrong version');
+ }
+ if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) {
+ throw new Exception('wrong level');
+ }
+
+ $raw = new QRrawcode($input);
+
+ QRtools::markTime('after_raw');
+
+ $version = $raw->version;
+ $width = QRspec::getWidth($version);
+ $frame = QRspec::newFrame($version);
+
+ $filler = new FrameFiller($width, $frame);
+ if(is_null($filler)) {
+ return NULL;
+ }
+
+ // inteleaved data and ecc codes
+ for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) {
+ $code = $raw->getCode();
+ $bit = 0x80;
+ for($j=0; $j<8; $j++) {
+ $addr = $filler->next();
+ $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
+ $bit = $bit >> 1;
+ }
+ }
+
+ QRtools::markTime('after_filler');
+
+ unset($raw);
+
+ // remainder bits
+ $j = QRspec::getRemainder($version);
+ for($i=0; $i<$j; $i++) {
+ $addr = $filler->next();
+ $filler->setFrameAt($addr, 0x02);
+ }
+
+ $frame = $filler->frame;
+ unset($filler);
+
+
+ // masking
+ $maskObj = new QRmask();
+ if($mask < 0) {
+
+ if (QR_FIND_BEST_MASK) {
+ $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());
+ } else {
+ $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
+ }
+ } else {
+ $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());
+ }
+
+ if($masked == NULL) {
+ return NULL;
+ }
+
+ QRtools::markTime('after_mask');
+
+ $this->version = $version;
+ $this->width = $width;
+ $this->data = $masked;
+
+ return $this;
+ }
+
+ //----------------------------------------------------------------------
+ public function encodeInput(QRinput $input)
+ {
+ return $this->encodeMask($input, -1);
+ }
+
+ //----------------------------------------------------------------------
+ public function encodeString8bit($string, $version, $level)
+ {
+ if(string == NULL) {
+ throw new Exception('empty string!');
+ return NULL;
+ }
+
+ $input = new QRinput($version, $level);
+ if($input == NULL) return NULL;
+
+ $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string));
+ if($ret < 0) {
+ unset($input);
+ return NULL;
+ }
+ return $this->encodeInput($input);
+ }
+
+ //----------------------------------------------------------------------
+ public function encodeString($string, $version, $level, $hint, $casesensitive)
+ {
+
+ if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) {
+ throw new Exception('bad hint');
+ return NULL;
+ }
+
+ $input = new QRinput($version, $level);
+ if($input == NULL) return NULL;
+
+ $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive);
+ if($ret < 0) {
+ return NULL;
+ }
+
+ return $this->encodeInput($input);
+ }
+
+ //----------------------------------------------------------------------
+ public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false)
+ {
+ $enc = QRencode::factory($level, $size, $margin);
+ return $enc->encodePNG($text, $outfile, $saveandprint=false);
+ }
+
+ //----------------------------------------------------------------------
+ public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4)
+ {
+ $enc = QRencode::factory($level, $size, $margin);
+ return $enc->encode($text, $outfile);
+ }
+
+ //----------------------------------------------------------------------
+ public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4)
+ {
+ $enc = QRencode::factory($level, $size, $margin);
+ return $enc->encodeRAW($text, $outfile);
+ }
+ }
+
+ //##########################################################################
+
+ class FrameFiller {
+
+ public $width;
+ public $frame;
+ public $x;
+ public $y;
+ public $dir;
+ public $bit;
+
+ //----------------------------------------------------------------------
+ public function __construct($width, &$frame)
+ {
+ $this->width = $width;
+ $this->frame = $frame;
+ $this->x = $width - 1;
+ $this->y = $width - 1;
+ $this->dir = -1;
+ $this->bit = -1;
+ }
+
+ //----------------------------------------------------------------------
+ public function setFrameAt($at, $val)
+ {
+ $this->frame[$at['y']][$at['x']] = chr($val);
+ }
+
+ //----------------------------------------------------------------------
+ public function getFrameAt($at)
+ {
+ return ord($this->frame[$at['y']][$at['x']]);
+ }
+
+ //----------------------------------------------------------------------
+ public function next()
+ {
+ do {
+
+ if($this->bit == -1) {
+ $this->bit = 0;
+ return array('x'=>$this->x, 'y'=>$this->y);
+ }
+
+ $x = $this->x;
+ $y = $this->y;
+ $w = $this->width;
+
+ if($this->bit == 0) {
+ $x--;
+ $this->bit++;
+ } else {
+ $x++;
+ $y += $this->dir;
+ $this->bit--;
+ }
+
+ if($this->dir < 0) {
+ if($y < 0) {
+ $y = 0;
+ $x -= 2;
+ $this->dir = 1;
+ if($x == 6) {
+ $x--;
+ $y = 9;
+ }
+ }
+ } else {
+ if($y == $w) {
+ $y = $w - 1;
+ $x -= 2;
+ $this->dir = -1;
+ if($x == 6) {
+ $x--;
+ $y -= 8;
+ }
+ }
+ }
+ if($x < 0 || $y < 0) return null;
+
+ $this->x = $x;
+ $this->y = $y;
+
+ } while(ord($this->frame[$y][$x]) & 0x80);
+
+ return array('x'=>$x, 'y'=>$y);
+ }
+
+ } ;
+
+ //##########################################################################
+
+ class QRencode {
+
+ public $casesensitive = true;
+ public $eightbit = false;
+
+ public $version = 0;
+ public $size = 3;
+ public $margin = 4;
+
+ public $structured = 0; // not supported yet
+
+ public $level = QR_ECLEVEL_L;
+ public $hint = QR_MODE_8;
+
+ //----------------------------------------------------------------------
+ public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4)
+ {
+ $enc = new QRencode();
+ $enc->size = $size;
+ $enc->margin = $margin;
+
+ switch ($level.'') {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ $enc->level = $level;
+ break;
+ case 'l':
+ case 'L':
+ $enc->level = QR_ECLEVEL_L;
+ break;
+ case 'm':
+ case 'M':
+ $enc->level = QR_ECLEVEL_M;
+ break;
+ case 'q':
+ case 'Q':
+ $enc->level = QR_ECLEVEL_Q;
+ break;
+ case 'h':
+ case 'H':
+ $enc->level = QR_ECLEVEL_H;
+ break;
+ }
+
+ return $enc;
+ }
+
+ //----------------------------------------------------------------------
+ public function encodeRAW($intext, $outfile = false)
+ {
+ $code = new QRcode();
+
+ if($this->eightbit) {
+ $code->encodeString8bit($intext, $this->version, $this->level);
+ } else {
+ $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
+ }
+
+ return $code->data;
+ }
+
+ //----------------------------------------------------------------------
+ public function encode($intext, $outfile = false)
+ {
+ $code = new QRcode();
+
+ if($this->eightbit) {
+ $code->encodeString8bit($intext, $this->version, $this->level);
+ } else {
+ $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
+ }
+
+ QRtools::markTime('after_encode');
+
+ if ($outfile!== false) {
+ file_put_contents($outfile, join("\n", QRtools::binarize($code->data)));
+ } else {
+ return QRtools::binarize($code->data);
+ }
+ }
+
+ //----------------------------------------------------------------------
+ public function encodePNG($intext, $outfile = false,$saveandprint=false)
+ {
+ try {
+
+ ob_start();
+ $tab = $this->encode($intext);
+ $err = ob_get_contents();
+ ob_end_clean();
+
+ if ($err != '')
+ QRtools::log($outfile, $err);
+
+ $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
+
+ QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint);
+
+ } catch (Exception $e) {
+
+ QRtools::log($outfile, $e->getMessage());
+
+ }
+ }
+ }
+ + diff --git a/apps/shorty/ajax/add.php b/apps/shorty/ajax/add.php new file mode 100644 index 00000000000..b1130e47db6 --- /dev/null +++ b/apps/shorty/ajax/add.php @@ -0,0 +1,101 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU AFFERO GENERAL PUBLIC LICENSE (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file ajax/add.php + * @brief Ajax method to add a new shorty defined by request arguments + * @param title (string) Human readable title of the shorty + * @param target (url) Remote target url meant to be shortened + * @param until (date) Date until when the created shorty is valid and usable + * @param notes (string) Any additional information in text form + * @param favicon (url) Reference to the shortcut icon used in target url + * @returns (json) success/error state indicator + * @returns (json) Associative array of attributes of the generated shorty + * @returns (json) Human readable message + * @author Christian Reiner + */ + +// swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure +OC_Shorty_Tools::ob_control ( TRUE ); + + //no apps or filesystem +$RUNTIME_NOSETUPFS = true; + +// Check if we are a user +OCP\JSON::checkLoggedIn ( ); +OCP\JSON::checkAppEnabled ( 'shorty' ); + +try +{ + $p_id = OC_Shorty_Tools::shorty_id ( ); + $p_status = OC_Shorty_Type::req_argument ( 'status', OC_Shorty_Type::STATUS, FALSE ); + $p_title = OC_Shorty_Type::req_argument ( 'title', OC_Shorty_Type::STRING, FALSE ); + $p_target = OC_Shorty_Type::req_argument ( 'target', OC_Shorty_Type::URL, TRUE ); + $p_until = OC_Shorty_Type::req_argument ( 'until', OC_Shorty_Type::DATE, FALSE ); + $p_notes = OC_Shorty_Type::req_argument ( 'notes', OC_Shorty_Type::STRING, FALSE ); + $p_favicon = OC_Shorty_Type::req_argument ( 'favicon', OC_Shorty_Type::URL, FALSE ); + // register shorty at backend + $p_source = OC_Shorty_Backend::registerUrl ( $p_id ); + // fallback title: choose hostname if no title is specified + $p_title = $p_title ? trim($p_title) : parse_url($p_target,PHP_URL_HOST); + // insert new shorty into our database + $param = array + ( + ':user' => OCP\User::getUser(), + ':id' => $p_id, + ':status' => $p_status ? $p_status : '', + ':title' => $p_title ? $p_title : '', + ':favicon' => $p_favicon ? $p_favicon : '', + ':source' => $p_source ? $p_source : '', + ':target' => $p_target ? $p_target : '', + ':notes' => $p_notes ? $p_notes : '', + ':until' => $p_until, + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_INSERT ); + $query->execute ( $param ); + + // read new entry for feedback + $param = array + ( + ':user' => OCP\User::getUser(), + ':id' => $p_id, + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_VERIFY ); + $entries = $query->execute($param)->FetchAll(); + if ( (1==count($entries)) + &&(isset($entries[0]['id'])) + &&($p_id==$entries[0]['id']) ) + $entries[0]['relay']=OC_Shorty_Tools::relayUrl ( $entries[0]['id'] ); + else + throw new OC_Shorty_Exception ( "failed to verify stored shorty with id '%1s'", array($p_id) ); + + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); + OCP\Util::writeLog( 'shorty', sprintf("Url shortened to: %s",$p_source), OC_Log::INFO ); + OCP\JSON::success ( array ( 'data' => $entries[0], + 'message' => OC_Shorty_L10n::t("Url shortened to: %s",$p_source) ) ); +} catch ( Exception $e ) { OC_Shorty_Exception::JSONerror($e); } +?> diff --git a/apps/shorty/ajax/click.php b/apps/shorty/ajax/click.php new file mode 100644 index 00000000000..c88f6eec4f5 --- /dev/null +++ b/apps/shorty/ajax/click.php @@ -0,0 +1,67 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file ajax/click.php + * @brief Ajax method to register a 'click', a single hit on an existing and valid shorty + * @param id (string) Internal id of a referenced shorty + * @returns (json) success/error state indicator + * @returns (json) Associative array holding the id of the shorty whose click was registered + * @author Christian Reiner + */ + +// swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure +OC_Shorty_Tools::ob_control ( TRUE ); + +//no apps or filesystem +$RUNTIME_NOSETUPFS = true; + +// Check if we are a user +OCP\JSON::checkLoggedIn ( ); +OCP\JSON::checkAppEnabled ( 'shorty' ); + +try +{ + if (isset($_GET['id'])) + { + $p_id = OC_Shorty_Type::req_argument ( $_GET['id'], OC_Shorty_Type::ID, TRUE ); + $param = array + ( + 'user' => OCP\User::getUser(), + 'id' => $p_id, + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_CLICK ); + $query->execute ( $param ); + OCP\JSON::success ( array ( 'data' => array('id'=>$p_id), + 'message' => OC_Shorty_L10n::t('Click registered') ) ); + } + else + throw new OC_Shorty_Exception ( "request failed: missing mandatory argument 'id'" ); + + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); +} catch ( Exception $e ) { OC_Shorty_Exception::JSONerror($e); } +?> diff --git a/apps/shorty/ajax/count.php b/apps/shorty/ajax/count.php new file mode 100644 index 00000000000..9a00083bb9f --- /dev/null +++ b/apps/shorty/ajax/count.php @@ -0,0 +1,54 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file ajax/count.php + * @brief Ajax method to retrieve a list of important sums, counts of the existing set of shortys + * @returns (json) success/error state indicator + * @returns (json) Associative array of counts + * @author Christian Reiner + */ + +// swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure +OC_Shorty_Tools::ob_control ( TRUE ); + +//no apps or filesystem +$RUNTIME_NOSETUPFS = TRUE; + +// Check if we are a user +OCP\JSON::checkLoggedIn ( ); +OCP\JSON::checkAppEnabled ( 'shorty' ); + +try +{ + $countResult = OC_Shorty_Tools::countShorties ( ); + + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); + OCP\JSON::success ( array ( 'data' => $countResult, + 'message' => OC_Shorty_L10n::t('Counted entries and clicks') ) ); +} catch ( Exception $e ) { OC_Shorty_Exception::JSONerror($e); } +?> diff --git a/apps/shorty/ajax/del.php b/apps/shorty/ajax/del.php new file mode 100644 index 00000000000..b24f83915ed --- /dev/null +++ b/apps/shorty/ajax/del.php @@ -0,0 +1,63 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file ajax/del.php + * @brief Ajax method to delete an existing shorty + * @param id (string) Internal id of a referenced shorty + * @returns (json) success/error state indicator + * @returns (json) Key of shorty that was deleted + * @author Christian Reiner + */ + +// swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure +OC_Shorty_Tools::ob_control ( TRUE ); + +//no apps or filesystem +$RUNTIME_NOSETUPFS = true; + +// Check if we are a user +OCP\JSON::checkLoggedIn ( ); +OCP\JSON::checkAppEnabled ( 'shorty' ); + +try +{ + $p_id = OC_Shorty_Type::req_argument ( 'id', OC_Shorty_Type::ID, TRUE ); + $param = array + ( + 'user' => OCP\User::getUser(), + 'id' => $p_id, + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_DELETE ); + $query->execute($param); + + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); + OCP\Util::writeLog( 'shorty', sprintf("Shorty with id '%s' deleted",$p_id), OC_Log::INFO ); + OCP\JSON::success ( array ( 'data' => array('id'=>$p_id), + 'message' => OC_Shorty_L10n::t("Shorty with id '%s' deleted",$p_id) ) ); +} catch ( Exception $e ) { OC_Shorty_Exception::JSONerror($e); } +?> diff --git a/apps/shorty/ajax/edit.php b/apps/shorty/ajax/edit.php new file mode 100644 index 00000000000..252e4fe5c29 --- /dev/null +++ b/apps/shorty/ajax/edit.php @@ -0,0 +1,88 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file ajax/edit.php + * @brief Ajax method to modify aspects of an existing shorty + * @param id (string) Internal id of the referenced shorty + * @param title (string) Human readable title + * @param notes (string) Any additional information in free text form + * @returns (json) success/error state indicator + * @returns (json) Associative array holding the id of the shorty whose click was registered + * @author Christian Reiner + */ + +// swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure +OC_Shorty_Tools::ob_control ( TRUE ); + +//no apps or filesystem +$RUNTIME_NOSETUPFS = true; + +// Check if we are a user +OCP\JSON::checkLoggedIn ( ); +OCP\JSON::checkAppEnabled ( 'shorty' ); + +try +{ + $p_id = OC_Shorty_Type::req_argument ( 'id', OC_Shorty_Type::ID, TRUE ); + $p_status = OC_Shorty_Type::req_argument ( 'status', OC_Shorty_Type::STATUS, FALSE ); + $p_title = OC_Shorty_Type::req_argument ( 'title', OC_Shorty_Type::STRING, FALSE ); + $p_until = OC_Shorty_Type::req_argument ( 'until', OC_Shorty_Type::DATE, FALSE ); + $p_notes = OC_Shorty_Type::req_argument ( 'notes', OC_Shorty_Type::STRING, FALSE ); + $param = array + ( + ':user' => OCP\User::getUser ( ), + ':id' => $p_id, + ':status'=> $p_status ? $p_status : '', + ':title' => $p_title ? $p_title : '', + ':notes' => $p_notes ? $p_notes : '', + ':until' => $p_until, + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_UPDATE ); + $query->execute ( $param ); + + // read new entry for feedback + $param = array + ( + 'user' => OCP\User::getUser(), + 'id' => $p_id, + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_VERIFY ); + $entries = $query->execute($param)->FetchAll(); + if ( (1==count($entries)) + &&(isset($entries[0]['id'])) + &&($p_id==$entries[0]['id']) ) + $entries[0]['relay']=OC_Shorty_Tools::relayUrl ( $entries[0]['id'] ); + else + throw new OC_Shorty_Exception ( "failed to verify stored shorty with id '%1s'", array($p_id) ); + + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); + OCP\Util::writeLog( 'shorty', sprintf("Modifications for shorty with id '%s' saved",$p_id), OC_Log::INFO ); + OCP\JSON::success ( array ( 'data' => $entries[0], + 'message' => OC_Shorty_L10n::t("Modifications for shorty with id '%s' saved",$p_id) ) ); +} catch ( Exception $e ) { OC_Shorty_Exception::JSONerror($e); } +?> diff --git a/apps/shorty/ajax/list.php b/apps/shorty/ajax/list.php new file mode 100644 index 00000000000..8b4e9b3e81e --- /dev/null +++ b/apps/shorty/ajax/list.php @@ -0,0 +1,77 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file ajax/list.php + * @brief Ajax method to retrieve a list of existing shortys + * @returns (json) success/error state indicator + * @returns (number) Total number of shortys in the list + * @returns (json) Numeric array of all shortys, associative array of attributes as values for every single shorty contained + * @author Christian Reiner + */ + +// swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure +OC_Shorty_Tools::ob_control ( TRUE ); + +//no apps or filesystem +$RUNTIME_NOSETUPFS = TRUE; + +// Check if we are a user +OCP\JSON::checkLoggedIn ( ); +OCP\JSON::checkAppEnabled ( 'shorty' ); + +try +{ + // first remove any entries already marked as 'deleted' + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_REMOVE ); + $result = $query->execute(array(':user'=>OCP\User::getUser())); + // now comes the real list selection +// define ('PAGE_SIZE', 100); +// $p_offset = OC_Shorty_Type::req_argument ( 'page', OC_Shorty_Type::INTEGER, FALSE) * PAGE_SIZE; + // pre-sort list according to user preferences + $p_sort = OC_Shorty_Type::$SORTING[OCP\Config::getUserValue(OCP\User::getUser(),'shorty','list-sort-code','cd')]; + $param = array + ( + ':user' => OCP\User::getUser ( ), + ':sort' => $p_sort, +// ':offset' => $p_offset, +// ':limit' => PAGE_SIZE, + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_LIST ); + $result = $query->execute($param); + $reply = $result->fetchAll(); + // enhance all entries with the relay url + foreach (array_keys($reply) as $key) + if (isset($reply[$key]['id'])) + $reply[$key]['relay']=OC_Shorty_Tools::relayUrl ( $reply[$key]['id'] ); + + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); + OCP\JSON::success ( array ( 'data' => $reply, + 'count' => sizeof($reply), + 'message' => OC_Shorty_L10n::t('Number of entries: %s', count($reply)) ) ); +} catch ( Exception $e ) { OC_Shorty_Exception::JSONerror($e); } +?> diff --git a/apps/shorty/ajax/meta.php b/apps/shorty/ajax/meta.php new file mode 100644 index 00000000000..5f9d5c3c315 --- /dev/null +++ b/apps/shorty/ajax/meta.php @@ -0,0 +1,56 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file ajax/meta.php + * @brief Ajax method to query meta information about a given remote url + * @param target (string) Url of a remote web resource + * @returns (json) success/error state indicator + * @returns (array) Associative array of meta data aspects + * @author Christian Reiner + */ + +// swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure +OC_Shorty_Tools::ob_control ( TRUE ); + +//no apps or filesystem +$RUNTIME_NOSETUPFS = true; + +// Check if we are a user +OCP\JSON::checkLoggedIn ( ); +OCP\JSON::checkAppEnabled ( 'shorty' ); + +try +{ + $target = OC_Shorty_Type::req_argument ( 'target', OC_Shorty_Type::URL, TRUE ); + $meta = OC_Shorty_Meta::fetchMetaData(htmlspecialchars_decode($target)); + + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); + OCP\JSON::success ( array ( 'data' => $meta, + 'message' => OC_Shorty_L10n::t("Target url '%s' is valid", $meta['target']) ) ); +} catch ( Exception $e ) { OC_Shorty_Exception::JSONerror($e); } +?> diff --git a/apps/shorty/ajax/preferences.php b/apps/shorty/ajax/preferences.php new file mode 100644 index 00000000000..e35a2f7aff3 --- /dev/null +++ b/apps/shorty/ajax/preferences.php @@ -0,0 +1,119 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file ajax/preferences.php + * @brief Ajax method to store one or more personal preferences + * @param backend-type (string) Identifier of chosen backend type + * @param backend-static-base (string) Url to use as a base when the static backend is active + * @param backend-google-key (string) Personal authentication key to use when the google backend is active + * @param backend-bitly-key (string) Personal authentication key to use when the bit.li backend is active + * @param backend-bitly-user (string) Personal authentication user to use when the bit.li backend is active + * @param sms-control (string) Controls wether a 'send as sms' action should be offered is the sharing dialog + * @param list-sort-code (string) Two character sorting key controlling the active sorting of shorty lists + * @returns (json) success/error state indicator + * @returns (json) Associative array holding the stored values by their key + * @returns (json) Human readable message describing the result + * @author Christian Reiner + */ + +// swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure +OC_Shorty_Tools::ob_control ( TRUE ); + +//no apps or filesystem +$RUNTIME_NOSETUPFS = true; + +// Check if we are a user +OCP\JSON::checkLoggedIn ( ); +OCP\JSON::checkAppEnabled ( 'shorty' ); + +try +{ + $data = array(); + switch ( $_SERVER['REQUEST_METHOD'] ) + { + case 'POST': + // detect provided preferences + $data = array(); + foreach (array_keys($_POST) as $key) + if ( isset(OC_Shorty_Type::$PREFERENCE[$key]) ) // ignore unknown preference keys + { + $type = OC_Shorty_Type::$PREFERENCE[$key]; + $data[$key] = OC_Shorty_Type::req_argument ( $key, $type, FALSE ); + } + // eliminate settings not explicitly set + $data = array_diff ( $data, array(FALSE) ); + // store settings + foreach ( $data as $key=>$val ) + OCP\Config::setUserValue( OCP\User::getUser(), 'shorty', $key, $val ); + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); + OCP\Util::writeLog( 'shorty', sprintf("Preference(s) '%s' saved.",implode(',',array_keys($data))), OC_Log::INFO ); + OCP\JSON::success ( array ( 'data' => $data, + 'message' => OC_Shorty_L10n::t("Preference(s) '%s' saved.",implode(',',array_keys($data))) ) ); + break; + case 'GET': + // detect requested preferences + foreach (array_keys($_GET) as $key) + { + if ( isset(OC_Shorty_Type::$PREFERENCE[$key]) ) // ignore unknown preference keys + { + $type = OC_Shorty_Type::$PREFERENCE[$key]; + $data[$key] = OCP\Config::getUserValue( OCP\User::getUser(), 'shorty', $key); + // morph value into an explicit type + switch ($type) + { + case OC_Shorty_Type::ID: + case OC_Shorty_Type::STATUS: + case OC_Shorty_Type::SORTKEY: + case OC_Shorty_Type::SORTVAL: + case OC_Shorty_Type::STRING: + case OC_Shorty_Type::URL: + case OC_Shorty_Type::DATE: + settype ( $data[$key], 'string' ); + break; + case OC_Shorty_Type::INTEGER: + case OC_Shorty_Type::TIMESTAMP: + settype ( $data[$key], 'integer' ); + break; + case OC_Shorty_Type::FLOAT: + settype ( $data[$key], 'float' ); + break; + default: + } // switch + } + } // foreach + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); + OCP\Util::writeLog( 'shorty', sprintf("Preference(s) '%s' saved.",implode(',',array_keys($data))), OC_Log::INFO ); + OCP\JSON::success ( array ( 'data' => $data, + 'message' => OC_Shorty_L10n::t('Preference(s) retrieved.') ) ); + break; + default: + throw new OC_Shorty_Exception ( "unexpected request method '%s'", $_SERVER['REQUEST_METHOD'] ); + } // switch +} catch ( Exception $e ) { OC_Shorty_Exception::JSONerror($e); } +?> diff --git a/apps/shorty/ajax/settings.php b/apps/shorty/ajax/settings.php new file mode 100644 index 00000000000..af76b69e076 --- /dev/null +++ b/apps/shorty/ajax/settings.php @@ -0,0 +1,109 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file ajax/settings.php + * @brief Ajax method to store one or more system settings (plugin settings) + * @param backend-static-base (string) Url to use as a base when the static backend is active (plugins default, may be overridden by user preference) + * @returns (json) success/error state indicator + * @returns (json) Associative array holding the stored values by their key + * @returns (json) Human readable message describing the result + * @author Christian Reiner + */ + +// swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure +OC_Shorty_Tools::ob_control ( TRUE ); + +//no apps or filesystem +$RUNTIME_NOSETUPFS = true; + +// Check if we are a user +OCP\JSON::checkAdminUser ( ); +OCP\JSON::checkAppEnabled ( 'shorty' ); + +try +{ + $data = array(); + switch ( $_SERVER['REQUEST_METHOD'] ) + { + case 'POST': + // detect provided settings + $data = array(); + foreach (array_keys($_POST) as $key) + if ( isset(OC_Shorty_Type::$SETTING[$key]) ) // ignore unknown preference keys + { + $type = OC_Shorty_Type::$SETTING[$key]; + $data[$key] = OC_Shorty_Type::req_argument ( $key, $type, FALSE ); + } + // eliminate settings not explicitly set + $data = array_diff ( $data, array(FALSE) ); + // store settings one by one + foreach ( $data as $key=>$val ) + OCP\Config::setAppValue( 'shorty', $key, $val ); + break; + case 'GET': + // detect requested settings + foreach (array_keys($_GET) as $key) + { + if ( isset(OC_Shorty_Type::$SETTING[$key]) ) // ignore unknown preference keys + { + $type = OC_Shorty_Type::$SETTING[$key]; + $data[$key] = OCP\Config::getUserValue( OCP\User::getUser(), 'shorty', $key); + // morph value into an explicit type + switch ($type) + { + case OC_Shorty_Type::ID: + case OC_Shorty_Type::STATUS: + case OC_Shorty_Type::SORTKEY: + case OC_Shorty_Type::SORTVAL: + case OC_Shorty_Type::STRING: + case OC_Shorty_Type::URL: + case OC_Shorty_Type::DATE: + settype ( $data[$key], 'string' ); + break; + case OC_Shorty_Type::INTEGER: + case OC_Shorty_Type::TIMESTAMP: + settype ( $data[$key], 'integer' ); + break; + case OC_Shorty_Type::FLOAT: + settype ( $data[$key], 'float' ); + break; + default: + } // switch + } + } // foreach + break; + default: + throw new OC_Shorty_Exception ( "unexpected request method '%s'", $_SERVER['REQUEST_METHOD'] ); + } // switch + + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); + OCP\Util::writeLog( 'shorty', sprintf("Setting(s) '%s' saved.",implode(',',array_keys($data))), OC_Log::INFO ); + OCP\JSON::success ( array ( 'data' => $data, + 'message' => OC_Shorty_L10n::t('Setting saved.') ) ); +} catch ( Exception $e ) { OC_Shorty_Exception::JSONerror($e); } +?> diff --git a/apps/shorty/ajax/status.php b/apps/shorty/ajax/status.php new file mode 100644 index 00000000000..6d00bf58854 --- /dev/null +++ b/apps/shorty/ajax/status.php @@ -0,0 +1,67 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file ajax/status.php + * @brief Ajax method to modify the status of an existing shorty + * @param id (string) Internal id of the referenced shorty + * @param title (string) Human readable title + * @param notes (string) Any additional information in free text form + * @returns (json) success/error state indicator + * @returns (json) Associative array holding the id of the shorty whose click was registered + * @author Christian Reiner + */ + +// swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure +OC_Shorty_Tools::ob_control ( TRUE ); + +//no apps or filesystem +$RUNTIME_NOSETUPFS = true; + +// Check if we are a user +OCP\JSON::checkLoggedIn ( ); +OCP\JSON::checkAppEnabled ( 'shorty' ); + +try +{ + $p_id = OC_Shorty_Type::req_argument ( 'id', OC_Shorty_Type::ID, TRUE ); + $p_status = OC_Shorty_Type::req_argument ( 'status', OC_Shorty_Type::STATUS, FALSE ); + $param = array + ( + 'user' => OCP\User::getUser ( ), + 'id' => $p_id, + 'status' => $p_status, + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_STATUS ); + $query->execute ( $param ); + + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + OC_Shorty_Tools::ob_control ( FALSE ); + OCP\Util::writeLog( 'shorty', sprintf("Status change for shorty with id '%s' saved",$p_id), OC_Log::INFO ); + OCP\JSON::success ( array ( 'data' => array('id'=>$p_id), + 'message' => sprintf(OC_Shorty_L10n::t("Status change for shorty with id '%s' saved"),$p_id) ) ); +} catch ( Exception $e ) { OC_Shorty_Exception::JSONerror($e); } +?> diff --git a/apps/shorty/appinfo/app.php b/apps/shorty/appinfo/app.php new file mode 100644 index 00000000000..635fda4ee27 --- /dev/null +++ b/apps/shorty/appinfo/app.php @@ -0,0 +1,53 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file appinfo/app.php + * @brief Basic registration of plugin at ownCloud + * @author Christian Reiner + */ + +OC::$CLASSPATH['OC_Shorty_Backend'] = 'apps/shorty/lib/backend.php'; +OC::$CLASSPATH['OC_Shorty_Exception'] = 'apps/shorty/lib/exception.php'; +OC::$CLASSPATH['OC_Shorty_HttpException'] = 'apps/shorty/lib/exception.php'; +OC::$CLASSPATH['OC_Shorty_L10n'] = 'apps/shorty/lib/l10n.php'; +OC::$CLASSPATH['OC_Shorty_Meta'] = 'apps/shorty/lib/meta.php'; +OC::$CLASSPATH['OC_Shorty_Query'] = 'apps/shorty/lib/query.php'; +OC::$CLASSPATH['OC_Shorty_Tools'] = 'apps/shorty/lib/tools.php'; +OC::$CLASSPATH['OC_Shorty_Type'] = 'apps/shorty/lib/type.php'; + +OCP\App::addNavigationEntry ( array ( 'id' => 'shorty_index', + 'order' => 71, + 'href' => OCP\Util::linkTo ( 'shorty', 'index.php' ), + 'icon' => OCP\Util::imagePath( 'shorty', 'shorty.svg' ), + 'name' => 'Shorty' ) ); + +OCP\App::register ( array ( 'order' => 71, 'id' => 'shorty', 'name' => 'Shorty' ) ); +OCP\App::registerAdmin ( 'shorty', 'settings' ); +OCP\App::registerPersonal ( 'shorty', 'preferences' ); +OCP\Util::connectHook ( 'OC_User', 'post_deleteUser', 'OC_Shorty_Hooks', 'deleteUser'); + +?> diff --git a/apps/shorty/appinfo/database.xml b/apps/shorty/appinfo/database.xml new file mode 100644 index 00000000000..0cac24dbf25 --- /dev/null +++ b/apps/shorty/appinfo/database.xml @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!-- +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +--> + +<!-- + /** + * @file appinfo/database.xml + * @brief Database scheme definition for plugins tables + * @author Christian Reiner + */ + --> + +<database> + <name>*dbname*</name> + <create>true</create> + <overwrite>false</overwrite> + <charset>latin1</charset> + <table> + <name>*dbprefix*shorty</name> + <declaration> + <field> + <name>id</name> + <type>text</type> + <notnull>true</notnull> + <length>12</length> + </field> + <field> + <name>status</name> + <type>text</type> + <default>'shared'</default> + <notnull>true</notnull> + <length>10</length> + </field> + <field> + <name>title</name> + <type>text</type> + <default>''</default> + <notnull>true</notnull> + <length>80</length> + </field> + <field> + <name>favicon</name> + <type>text</type> + <default>''</default> + <notnull>false</notnull> + <length>1024</length> + </field> + <field> + <name>source</name> + <type>text</type> + <notnull>true</notnull> + <length>4096</length> + </field> + <field> + <name>target</name> + <type>text</type> + <notnull>true</notnull> + <length>4096</length> + </field> + <field> + <name>user</name> + <type>text</type> + <notnull>true</notnull> + <length>64</length> + </field> + <field> + <name>until</name> + <type>date</type> + <notnull>false</notnull> + <default></default> + </field> + <field> + <name>created</name> + <type>date</type> + <notnull>false</notnull> + <default></default> + </field> + <field> + <name>accessed</name> + <type>timestamp</type> + <notnull>false</notnull> + <default></default> + </field> + <field> + <name>clicks</name> + <type>integer</type> + <default>0</default> + <notnull>true</notnull> + <unsigned>true</unsigned> + <length>10</length> + </field> + <field> + <name>notes</name> + <type>text</type> + <default>''</default> + <notnull>true</notnull> + <length>4096</length> + </field> + + <index> + <name>shorty_id</name> + <unique>true</unique> + <field> + <name>id</name> + <sorting>descending</sorting> + </field> + </index> + <index> + <name>shorty_user</name> + <unique>false</unique> + <field> + <name>user</name> + <sorting>ascending</sorting> + </field> + </index> + <index> + <name>shorty_source</name> + <unique>false</unique> + <field> + <name>source</name> + <sorting>ascending</sorting> + </field> + </index> + </declaration> + </table> +</database> diff --git a/apps/shorty/appinfo/info.xml b/apps/shorty/appinfo/info.xml new file mode 100644 index 00000000000..bbee9dd673b --- /dev/null +++ b/apps/shorty/appinfo/info.xml @@ -0,0 +1,56 @@ +<?xml version="1.0"?> +<!-- +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +--> + +<!-- + /** + * @file appinfo/info.xml + * @brief Definition of central information about this plugin + * @author Christian Reiner + /* + --> + +<info> + <id>shorty</id> + <name>Shorty</name> + <description>Shorty offers a service to store, manage and use a collection of short links +pointing to ressources in the web. The features are a combination of a +centralized bookmarks collection, an url shortener and an access control. +The collection is presented as a link of "shorties", a shorty can be created +either manually in the list ("New") or by using the "Shortlet". The Shortlet +is something like a Booklet, a JS based bookmark meant to be stored inside the +bookmark toolbar or area of a web browser. When clicked, the page currently +open in the browser will be offered to be added to the list of existing shorties. +For more information see: http://apps.owncloud.com/content/show.php/Shorty?content=150401 +Current version: 0.2.2 (06.06.2012)</description> + <version>0.2.2</version> + <licence>AGPL</licence> + <author>Christian Reiner</author> + <require>4</require> + <public> + <shorty_relay>relay.php</shorty_relay> + <shorty_qrcode>qrcode.php</shorty_qrcode> + </public> +</info> diff --git a/apps/shorty/appinfo/migrate.php b/apps/shorty/appinfo/migrate.php new file mode 100644 index 00000000000..5efce251a65 --- /dev/null +++ b/apps/shorty/appinfo/migrate.php @@ -0,0 +1,101 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file appinfo/migrate.php + * @brief OC migration support + * @author Christian Reiner + */ + +class OC_Migration_Provider_Shorty extends OC_Migration_Provider +{ + + function export ( ) + { + OCP\Util::writeLog ( 'migration','starting export for Shorty', OCP\Util::INFO ); + $options = array( + 'table'=>'shorty', + 'matchcol'=>'user', + 'matchval'=>$this->uid, + 'idcol'=>'id' + ); + $ids = $this->content->copyRows( $options ); + $count = OC_Shorty_Tools::countShorties(); + // check for success + if( (is_array($ids) && is_array($count)) + && (count($ids)==$count['sum_shortys']) ) + return true; + else return false; + } // function export + + function import ( ) + { + switch( $this->appinfo->version ) + { + default: + $query = $this->content->prepare( "SELECT * FROM shorty WHERE user_id LIKE ?" ); + $result = $query->execute( array( $this->olduid ) ); + if (is_array(is_array($result))) + { + while( $row = $result->fetchRow() ) + { + $param = array ( + 'id' => $row['id'], + 'status' => $row['status'], + 'title' => $row['title'], + 'favicon' => $row['favicon'], + 'source' => $row['source'], + 'target' => $row['target'], + 'user' => $row['user'], + 'until' => $row['until'], + 'created' => $row['created'], + 'accessed' => $row['accessed'], + 'clicks' => $row['clicks'], + 'notes' => $row['notes'], + ); + // import each shorty one by one, no special treatment required, since no autoincrement id is used + $query = OCP\DB::prepare( sprintf ( "INSERT INTO *PREFIX*shorty(%s) VALUES (%s)", + implode(',',array_keys($param)), + implode(',',array_fill(0,count($param),'?')) ) ); + $query->execute( $param ); + } // while + } // if + break; + } // switch + // check for success by counting the generated entries + $count = OC_Shorty_Tools::countShorties(); + if( (is_array($result) && is_array($count)) + && (count($result)==$count['sum_shortys']) ) + return true; + else return false; + } // function import + +} // class OC_Migration_Provider_Shorty + +// Load the provider +new OC_Migration_Provider_Shorty ( 'shortys' ); + +?> diff --git a/apps/shorty/css/preferences.css b/apps/shorty/css/preferences.css new file mode 100644 index 00000000000..37a86a534a6 --- /dev/null +++ b/apps/shorty/css/preferences.css @@ -0,0 +1,109 @@ +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file css/preferences.css + * @brief Style definitions for the user preference dialog + * @author Christian Reiner + */ + +#shorty img { + vertical-align: middle; + margin:0; + padding:0; +} +#shorty #shortlet { + outline: medium none; + padding: 0.6em 0.8em; + background-image: -moz-linear-gradient(center bottom, Lavender 0%, white 50%); + border: 1px solid #DDDDDD; + border-radius: 0.5em 0.5em 0.5em 0.5em; + box-shadow: 0 1px 0 #BBBBBB inset; +} +#shorty #shortlet a { + font-style: italic; + color: DarkSlateGray; +} +#shorty #shortlet:after { + content: url("%appswebroot%/apps/shorty/img/drag_me.png"); + position: relative; + top: -12px; + margin-left: -160px; +} +#shorty .chzn-container { + vertical-align: middle; +} + +#shorty .title { + margin-bottom: 0.6em; +} + +#shorty .aspect { + display: inline-block; + font-weight: bold; + width: 6em; + margin: 0 0.2em 0.4em 0; +} + +#shorty .explain { + display: inline-block; + font-style: italic; + margin: 0.3em; +} + +#shorty .example { + font-family: Monospace; + margin: 0.3em; +} + +#shorty a.external { + text-decoration:underline; +} +#shorty a.external:after { + content:url("%appswebroot%/apps/shorty/img/actions/external.png"); + margin-left:0.3em; +} + +#verification #hourglass { + display: block; + text-align: center; + width: 100%; height: 100%; + margin-top: 20px; +} + +#verification #failure { + display: none; + position: absolute; +} + +#verification #success { + display: none; + position: absolute; +} + +#verification legend { + width: 100%; + text-align: center; +} diff --git a/apps/shorty/css/settings.css b/apps/shorty/css/settings.css new file mode 100644 index 00000000000..e92031d8913 --- /dev/null +++ b/apps/shorty/css/settings.css @@ -0,0 +1,59 @@ +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file css/settings.css + * @brief Style definitions for the system settings dialog + * @author Christian Reiner + */ + +#shorty img { + vertical-align: middle; + margin:0; + padding:0; +} +#shorty .aspect { + display: inline-block; + font-weight: bold; + width: 6em; + margin: 0 0.2em 0.4em; +} + +#shorty .explain { + display: inline-block; + font-style: italic; + margin: 0.3em; +} + +#shorty .example { + font-family: Monospace; + margin: 0.3em; + text-decoration: underline; + color: blue; +} + +#shorty .title { + margin-bottom: 0.6em; +} diff --git a/apps/shorty/css/shorty.css b/apps/shorty/css/shorty.css new file mode 100644 index 00000000000..b071f06f77f --- /dev/null +++ b/apps/shorty/css/shorty.css @@ -0,0 +1,488 @@ +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file css/shorty.css + * @brief Style definitions of the plugins own view + * @author Christian Reiner + */ + +/* everything :-) */ +#content { overflow: auto; } + +/* a case sensitive help button */ +#content #controls #help { +/* float:right; */ +} +/* adapt optical appearance in case the help button is pushed into the header */ +#header #help { + float:right; + background-color:blue; +} + +/* the shorty desktop, a canvas, contains all elements except of those pushed into the header */ +#desktop { + display: inline-block; + position: absolute; +/* width: 100%; height: 100%; */ + background: transparent; + text-align: left; + margin-top: 30px; + padding: 2.5em 0.5em; + padding-top: 20px; +} +/* top bar, holding main control elements */ +#controls { + display: none; +} +/* a dialog for verification of the static backend setup */ +#verification { + overflow: hidden; +} +#verification p { + padding-bottom:0.4em; +} + +/* an activity visualizer, currently a 'rotating timer wheel' */ +#hourglass { + display: none; + position: absolute; + width: 100%; height: 100%; + z-index: 1; + background: transparent; +} +#hourglass img { + margin:4em 8em; +} +/* a replacement list visualized in case the 'real' list is empty */ +#vacuum { + display: none; + position: absolute; + left:8em; top:9em; + width: 100%; height: 100%; + z-index: 2; + white-space: nowrap; + font-style: italic; + background: transparent; +} +.shorty-standalone #busy { + display: none; + float: right; +} + +/* the list of shorties */ +#list { + display: inline; + position: absolute; + z-index: 3; + margin: 0.4em; + background: transparent; + table-layout: fixed; + width: 100%; +} +/* the collapsable toolbar below the lists column title row */ +#list thead #toolbar img { + cursor: pointer; + vertical-align: middle; +} +#list thead #toolbar img.shorty-sorter { + opacity:0.6; +} +/* last column in the list, content usually invisible, except when hovered */ +#list thead #toolbar img.shorty-active { + border:1px solid #888888; + border-radius: 0.3em; +} +#list thead tr:nth-child(2) > th { + padding-bottom:0.5em; +} +/* somewhat more fixed layout for the table */ +#list thead #titlebar th span { + display:inline-block; +} +#list tbody th#title, +#list tbody td#title, +#list tbody th#target, +#list tbody td#target { + width:10em; +} +#list thead #clicks span { + width:3em; +} +#list thead #until span { + width:5em; +} +#list thead #toolbar input, +#list thead #toolbar .chzn-container { + width:6em; + font-size: 11px; + margin: 0; + padding: 0.4em 0.3em 0.2em; + vertical-align: baseline; + background-color:#FFFFFF; +} + +/* column title apeparance */ +#list thead th { + font-weight: bold; + padding: 1px 6px; +} +#list thead th#clicks, +#list thead th#until, +#list thead th#actions { + text-align: center; +} +/* hide the dummy row */ +#list thead tr:last-child { display: none; } +/* hide the content of the 'actions' column, except when being hovered */ +#list tbody tr td span.shorty-actions { + visibility:visible; + opacity:0; + transition: opacity 500ms; + -moz-transition: opacity 500ms; + -webkit-transition: opacity 500ms; + -ms-transition: opacity 500ms; + -o-transition: opacity 500ms; + width:100px; + overflow:auto; +} +#list tbody tr:hover td span.shorty-actions { + opacity:1; + transition: opacity 500ms; + -moz-transition: opacity 500ms; + -webkit-transition: opacity 500ms; + -ms-transition: opacity 500ms; + -o-transition: opacity 500ms; +} +/* highlight a specific, 'clicked' row in the list */ +#list tbody tr.clicked { + border-radius: 0.5em; + background-color:#EEEEEE; + box-shadow: 0 0 0.5px #777777; + transition: background-color 500ms; + -moz-transition: background-color 500ms; + -webkit-transition: background-color 500ms; + -ms-transition: background-color 500ms; + -o-transition: background-color 500ms; +} +/* strike through visible content of rows (entries) marked as deleted */ +#list tbody tr.deleted>#title, +#list tbody tr.deleted>#target, +#list tbody tr.deleted>#clicks, +#list tbody tr.deleted>#until { + color: gray; + text-decoration: line-through; + background: transparent url('%appswebroot%/apps/shorty/img/status/strike.png') 0 50% repeat-x; +} +/* replace the 'delete' action icon by an 'undelete' icon */ +#list tbody tr.deleted>#actions #del:after { + content: url("%appswebroot%/apps/shorty/img/actions/recycle.png"); + position: relative; + top: 3px; + margin-left: -19px; + padding: 0; + opacity: 0; +} +#list tbody tr.deleted:hover>#actions #del>img { + opacity: 0; +} +#list tbody tr.deleted:hover>#actions #del:after { + opacity: 1; +} +/* general table cell appearance */ +#list tbody td { + padding: 1px 6px; +} +#list tbody td#until { + text-align: center; +} +#list tbody td#clicks { + text-align: right; + margin-right: 0.4em; +} +/* prettyfied select boxes */ +#content span.shorty-select select { + width: 6.4em; + margin: 0; + padding: 0.2em; + opacity:0.8; + border:0 none; + font-size: 10px; +} +#content span.shorty-select { + border: 1px solid #DDDDDD; + border-radius: 0.5em 0.5em 0.5em 0.5em; + box-shadow: 0 1px 1px #FFFFFF, 0 1px 0 #BBBBBB inset; + outline: medium none; + padding: 2px; +} +/* general style of interactive dialogs */ +.shorty-dialog { + display: none; + color: black; + border-bottom-left-radius: 1em; + border-bottom-right-radius: 1em; + box-shadow: 0 2px 1px #777777; + vertical-align:middle; + z-index:100; +} +.shorty-dialog fieldset { + position:relative; + border-bottom-left-radius: 0.5em; + border-bottom-right-radius: 0.5em; + border: 1px solid gray; + padding: 2px 4px 8px; +} +.shorty-dialog br { + clear: left; +} +.shorty-dialog legend { + font-weight: bold; + margin: 0 0 0 5px; + padding: 0 0.5em 0 0.2em; +} +.shorty-dialog legend a { + padding: 0; +} +.shorty-dialog textarea { + width: 80%; height: 5em; + background: none repeat scroll 0 0 #F8F8F8; + color: #555555; + border: 1px solid #DDDDDD; + border-radius: 0.5em; + cursor: text; + vertical-align:baseline; + margin: 0.3em; +} +.shorty-dialog textarea:hover, +.shorty-dialog textarea:active { + background-color: #FFFFFF; + color: #333333; + opacity: 1; +} +.shorty-dialog input { + width: 80%; +} +.shorty-dialog a, +.shorty-dialog input, +.shorty-dialog select, +.shorty-dialog textarea, +.shorty-dialog button { + padding: 0.4em 0.2em; +} +.shorty-dialog input[readonly], +.shorty-dialog select[readonly], +.shorty-dialog textarea[readonly], +.shorty-dialog button[readonly] { + border: 0 none; +/* box-shadow: 0 0 0; */ + box-shadow: 0 0 0 #FFFFFF; + outline: none; + background: none; + background-color: #F7F7F7; + padding: 0.3em 0.3em; +} +.shorty-dialog button#confirm { + width: 12em; height: 2em; + border: 1px solid lightgray; + background-color: #EEEEEE; +} +.shorty-dialog button#confirm.sharp { + background-color: white; +} +.shorty-dialog button#confirm.sharp:hover { +/* border-color: green; */ + border: 1px solid gray; +} + +/* dialogs floating above other content ('standing alone') */ +.shorty-standalone { + width: 46em; + margin: -1px 1em 0; + padding: 0.5em; + background: none repeat scroll 0 0 #F7F7F7; +} +.shorty-standalone fieldset { + width: 45em; +} +/* dialogs related to elements ('embedded in the content') */ +.shorty-embedded { + left: 6em; + width: 34em; + margin: -1px 4em 0; + padding: 0.5em; + background: none repeat scroll 0 0 #EEEEEE; + position: absolute; +} +.shorty-embedded fieldset { +/* width: 32em; */ +} +.shorty-embedded a#source, +.shorty-embedded a#relay, +.shorty-embedded a#target { + display: inline-block; + width: 26em; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + vertical-align: middle; +} +.shorty-embedded a.shorty-clickable:before { + content:url("%appswebroot%/apps/shorty/img/actions/external.png"); + margin-right:0.3em; +} +.shorty-embedded select { + margin: 0 0 0.2em 1.0em; + padding: 0.2em 0.4em 0.2em 0.2em; + border: 0 none; + background-color: #F4F4F4; +} +.shorty-embedded img.shorty-usage { + opacity: 0.6; + margin: 1em 1.5em 0.2em; + padding: 0; +} +.shorty-embedded img.shorty-usage.disabled { + opacity: 0.2; +} +.shorty-embedded img.shorty-usage:not(.disabled):hover { + cursor: pointer; +} +.shorty-dialog label { + display: inline-block; + clear:none; + width: 5.5em; + text-align: left; + vertical-align: baseline; + padding: 0.6em 0.5em 0.4em 0.3em; + cursor: default; +} +.shorty-dialog span { + padding: 0.6em 0.5em 0.4em 0.3em; +} +.shorty-dialog span.label-line { + display: inline; + clear: none; + margin: 0; + padding: 0; +} +/* elements (rows) freshly added to the list, this calss might trigger visual effects like pulsation */ +.shorty-fresh { + display: none; +} +/* elements (rows) currently filtered out (toolbars column filter options) */ +.shorty-filtered { + display: none; +} +/* style of all icons (as opposed to all images) */ +.shorty-icon { + display: inline; + background: transparent; + vertical-align: middle; + padding: 1px; +} +/* dim entries with expired 'until' dates */ +.shorty-expired { + color: gray; +} +/* but keep embedded dialogs readable */ +.shorty-expired .shorty-dialog { + color: black; +} +.shorty-expired img { + opacity : 0.2; +} +.shorty-expired .shorty-dialog img { + opacity : 1; +} +.shorty-expired #until { + text-decoration: line-through; +} +/* some general style flavours */ +.shorty-prompt { + margin-left: 4px; +} +.shorty-value { + margin-right: 4px; +} +.shorty-single { + padding: 0.5em 1em; +} +.shorty-single:hover { + background-color: #EAEAEA; +} +.shorty-single:hover .shorty-actions { + display: block; +} +.shorty-id { + color: black; +} +.shorty-date { + width: 40%; +} +.shorty-notes { + color: blue; + text-decoration: none; +} +.shorty-source { + color: gray; +} +.shorty-target { + color: green; +} +.shorty-meta { + margin: 0.1em; +} +/* close buttons in dialogs, embedded or standalone */ +.shorty-close-button { + display:inline; + float:left; + margin:0 0.8em 0 0.3em; + padding:0; +} +.shorty-close-button img { + vertical-align: middle; + margin:0; + padding:0; +} +/* unlike elsewhere we underline clickable links in dialogs */ +.shorty-clickable { + white-space: nowrap; + text-decoration: underline; +} +.shorty-framed { + display:inline-block; + padding:1em; + background-color:white; + border:1px solid black; +} +/* keep long entries like urls from disrupting the compact appearance of the list */ +.ellipsis { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + width: inherit; +}
\ No newline at end of file diff --git a/apps/shorty/doc/CHANGELOG b/apps/shorty/doc/CHANGELOG new file mode 100644 index 00000000000..b1b09b50fb8 --- /dev/null +++ b/apps/shorty/doc/CHANGELOG @@ -0,0 +1,59 @@ +***** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +***** + +Changelog: + +* Wed Jun 06 2012 Christian Reiner: version 0.2.2 +Added swallowing of accidential outputs during ajax requests. +This protects the replies JSON struction from being corrupted. +Additional server side log entries on level INFO +* Sat Jun 02 2012 Christian Reiner: version 0.2.1 +Fixed broken Shortlet +* Fri Jun 01 2012 Christian Reiner: version 0.2.0 +Support of ownCloud version 4 (app interface incompatible to prior versions) +Additional status 'private' for Shortys only accessible for the owner himself +Rudimentary SMS support for smart phones (more an assistance, can be disabled) +Additional QRCodes to publish Shorty source urls on the web (or elsewhere) +Data migration support as introduced by OC4 +Cleanup of Shortys upon user account deletion +* Sun May 28 2012 Christian Reiner: version 0.1.6 +Activation of Shorty sharing via SMS. +Enhanced backend descriptions. +* Sat Apr 28 2012 Christian Reiner: version 0.1.5 +Target url verification is less strict now, this way also more 'exotic' urls notations are accepted. +A few changes to the initilization scripts to prevent race conditions at startup. +Changed url specification in the Shortlet to prevent conflicts with a serverside suhosin protection. +* Fri Apr 27 2012 Christian Reiner: version 0.1.4 +Visualization of busy state in dialogs whilst fetch meta data from targets. +* Fri Apr 27 2012 Christian Reiner: version 0.1.3 +Prevented untimely submission of dialogs before having validated their contents. +* Fri Apr 27 2012 Christian Reiner: version 0.1.2 +Fixed race conditions during initialization. +* Thu Apr 26 2012 Christian Reiner: version 0.1.1 +Minor appearance corrections. +* Wed Apr 25 2012 Christian Reiner: version 0.1.0 +First official release. +* Tue Apr 24 2012 Christian Reiner: version 0.0.9 +Initial release. +Buggy, but some parts actually working. diff --git a/apps/shorty/doc/CONFIGURATION b/apps/shorty/doc/CONFIGURATION new file mode 100644 index 00000000000..2a7dab60d19 --- /dev/null +++ b/apps/shorty/doc/CONFIGURATION @@ -0,0 +1,113 @@ +***** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +***** + +There are five aspects that can be configured: +1.) System wide "static backend" (optional) +2.) Selection of a backend per user (optional) +3.) Import of the "shortlet" into a web browser (optional) +4.) Access control inside each single "shorty" (implicit) +5.) Sending of Shortys as SMS + +1.) System wide "static backend" (optional) +(Requires adminisstrative rights) +This optional setting enables a 'static backend'. That is a backend generting +source urls based on a static base url, thus the name. That base url should be +chosen as short as possible, since this defines the total length of all links +to be posted and used. Most likely the definition of that url requires the +configuration of rewrite rules on the server side. So it is only an option for +experienced adminsitrators with access to the server configuration, be it +centralized or based on decentralized per-directory rules (".htaccess files"). +A basic example is packed in the .htaccess file (might be hidden in a directory +listing because of the leading dot (.) in the name). The rules must be +configured such that all requests to urls of the scheme <base url><shorty key> +are mapped directly onto the web url of the shorty plugin +(http://<domain>/<owncloud>/apps/shorty/). The <shorty key> is a string, 6-12 +characters long, hard to predict. It is guaranteed to be unique throughout the +system (though in a technically crude manner...). The perfect situation for the +definition of a meaningful static backend would be a domain with a very short +name and configuration access to something close to the web root. +A random example is my own domain "christian-reiner.info". Since that is not +exactly short I would love to use the additional domain "c-r.info" for the sole +purpose of a static backend. Unfortunately that domain has been reserved by a +domain grabber who asks thousands of Euros for it ! So that's no option. At +least you should try to find a setup where the web path of the ownCloud +application is not part of the base url. So that you get something like +http://<domain name>/<shorty key>. +(Note that the shorty key is NOT part of the base url configuration). +You can easily test your setup any time by clicking on the example dynamically +visualized next to the configuration option. It runs a simple self-tests of the +setup in background. +There is no need that the base url must be served by the same http server that +serves the owncoud system. A static rewrite setup may well forward short source +urls to the shorty plugin inside a remote ownCloud installation. However, it is +a known issue that the internal validation of the setup won't work with such +scenario. + +2.) Selection of a backend per user (optional) +To generate the a source url that is part of every shorty the plugin uses a +backend. The configuration is done by using a preference option in the personal +preference section of the configuration. You can simply chose one of the +offered backends (combo box). Changing the backend does not affect any +previously generated shorties. Meaning they stay valid and usable and keep +their once defined source url. + +Different backends are implemented: +i.) "-none-" +As you have guessed this is something like a "dummy" backend without any +implemented logic. That means the source urls generated are exactly based on +the web url of the shorty plugin in your ownCloud system. This is not a very +clever setup, but it certainly works and keeps your data private. +ii.) "static backend" +If configured in the system administration a "static backend" is offered. For a +description see C-1. This backend typically offers shorter source urls, but its +setup required administrative rights on some http server system. +iii.) online services (url shorteners) +A few online services are offered as backends to generate short source urls. +Usage of some of those services requires you to open a free account at their +site. Detailed configuration requirements are displayed for the chosen backend. +If you don't care for details and just want short urls then have a try with the +tin.ny backend. No registration required, reliable service. But keep in mind +you depend on an external service as opposed to using a local static backend. + +3.) Import of the "shortlet" into a web browser (optional) +Shorty comes with a neat little "Shortlet" offered in the personal preferneces +section of ownCloud. It is a "button" you can import into your web browsers +bookmark toolbar or area by simple drag & drop. The Shortlet should work with +most modern browsers, though probably not all. Just have a try with it. + +4.) Access control inside each single "shorty" (implicit) +There are a few attributres you can configure freely inside each stored shorty: +- a title just shown inside the shorty plugin (serves recognition). +- a notes area, maybe you want to write down whom you send the shorty ? +- a status option that controls the usage of the shorty. + +5.) Sending of Shortys as SMS +Besides sending of Shortys as email message and copying a Shortys source url +to the clipboard a third action can be enabled inside the sharing dialog: +To send a Shortys source url as SMS. +However, the approach is extremely minimalistic, it relies on the client system +to correctly handle a 'sms url'. This is typically only given on a mobile +device, a smart phone. In addition, such url does not allow to specify a message +body, so the Shortys source url has to be copied and pasted manually. +The option is disabled by default. diff --git a/apps/shorty/doc/COPYRIGHT b/apps/shorty/doc/COPYRIGHT new file mode 100644 index 00000000000..5e501826f28 --- /dev/null +++ b/apps/shorty/doc/COPYRIGHT @@ -0,0 +1,23 @@ +***** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +***** diff --git a/apps/shorty/doc/CREDITS b/apps/shorty/doc/CREDITS new file mode 100644 index 00000000000..8f7a3dd037c --- /dev/null +++ b/apps/shorty/doc/CREDITS @@ -0,0 +1,32 @@ +***** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +***** + +The shorty plugin has been developed by: + +Christian Reiner, Hamburg, Germany +E-Mail: foss@christian-reiner.information + +Contributions: +I'd be more than happy to welcome all contributions to this little experiment. +Drop me a note, an idea, a patch, a good bottle of wine, anything ! diff --git a/apps/shorty/doc/INSTALLATION b/apps/shorty/doc/INSTALLATION new file mode 100644 index 00000000000..0a98605376a --- /dev/null +++ b/apps/shorty/doc/INSTALLATION @@ -0,0 +1,53 @@ +***** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +***** + +This package is a plugin for the ownCloud web application ("ownCloud app"). + +There are two ways of installation: automatic and manual + +* Automatic installation: +You need login to your ownCloud using an account with administrative rights. +Open the 'Apps' section of the adminstration and select 'shorty', enable it. +Then go on below with the basic configuration steps. + +* Manual installation: +Download the package from here: +http://apps.owncloud.com/content/show.php/Shorty?content=150401 +Create a subfolder 'shorty' in the "apps" subfolder of your ownCloud web root. +Unpack the contents of the package into the new folder 'shorty'. +Now load ownCloud in your favorite web browser and login with an administrative +account. +Enable the plugin in the "Apps" section of the configuration ("*") inside +ownClouds web gui (requires admin rights). + +* Basic configuration steps for BOTH types of installation: +The "Admin" section of the configuration allows to configure a base url to +enable usage of the static backend (see USAGE). +The "Preferences" section of that configuration now offers two elements: +- a "Shortlet" to be dragged to the browsers bookmark area (see USAGE). +- a configuration of a backend to use to generate source urls (see USAGE). +The main part of the plugin can be accessed in the navigation menu as "Shorty". + +*** +Have fun ! diff --git a/apps/shorty/doc/ISSUES b/apps/shorty/doc/ISSUES new file mode 100644 index 00000000000..083c4648636 --- /dev/null +++ b/apps/shorty/doc/ISSUES @@ -0,0 +1,58 @@ +***** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +***** + +This is a short list of known issues: + +- The datepicker popup in the edit dialog fails to set the expiration date: +I have no idea what the problem is. Exactly the same object works flawlessly +in the dialog to create a new shorty. I can't see any difference, except in +the edit dialog the date is taken from the existing row entry (working fine). +Maybe there is some sort of magic spell to awake a datepicker after changing +its date value ? No idea... + +- Clicking on a source or relay url from within the sharing dialog updates the +clicks counter and access time correctly, but the shown list entry is not +updated accordingly. + +- Shorty does not work in the konqueror web browser +All appears to be working fine except for one annoying thing: +the standalone dialogs won't open ! (show, create and edit entries) +Therefore Shorty is currently more or less useless in this browser. + +- Shorty does not work in the rekonq web browser +The basic navigation elements (menu left) work, but the desktop stays empty. +Apparently no script is executed, an issue with the js document.ready event. + +- It appears there is an issue with setting opacity in the Safari browser: +The status filter in the lists toolbar shows an ugly black brick instead of a +dimmed icon overlay. Also some other style issues appear, but the plugin seems +to be completely usable. + +- When internally validating the setup of the base url used in the static +backend you get a false positive ("doesn't work") although things are fine, if +the mapping of base url to shorty plugin is done via a redirect. This is for +exaple the case if you implement the mapping on a remote server because you +want to use a different domain name for statically shortened urls. +The reason is that jqueries ajax calls won't handle redirects internally. A +wrapper will have to be implemented. diff --git a/apps/shorty/doc/README b/apps/shorty/doc/README new file mode 100644 index 00000000000..4f590f30cd0 --- /dev/null +++ b/apps/shorty/doc/README @@ -0,0 +1,42 @@ +***** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +***** + +This "shorty" package implements a plugin for the ownCloud web application. +Shorty offers a service to store, manage and use a collection of short links +pointing to ressources in the web. The features are a combination of a +centralized bookmarks collection, an url shortener and a basic access control. +The collection is presented as a list of "shorties". A shorty can be created +either manually in the list ("New shorty") or by using the "Shortlet". The +Shortlet is something like a Bookmarklet, a script based bookmark meant to be +stored inside the bookmark collection of a web browser. When clicked, the page +currently open in the browser will be added to the list of existing shorties. + +Each Shorty contains a source and a target url. The source url can be used to +be posted in forums, sent inside an email message or whatever. It is typically +shorter than the target url, a full blown web url. But that actually depends +on the target url and the backend used. The target url is the ressource +identified by the shorty. Basic access control is implemented to control the +access of shorties posted to forums or sent per email, but not on a per user or +per group base. Existing shorties can be blocked for usage, set to expire on a +certain date and obviously can be removed permanently again. diff --git a/apps/shorty/doc/ROADMAP b/apps/shorty/doc/ROADMAP new file mode 100644 index 00000000000..b18099c9af2 --- /dev/null +++ b/apps/shorty/doc/ROADMAP @@ -0,0 +1,96 @@ +***** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +***** + +Future versions might implement additional features and services. Currently +planned are the following: + +* Ability to create Shortys directly from shared files inside ownCloud +Creating a Shorty based on the public url generated for shared files works like +charm. However it is not very convenient to do that manually. It would be great +to offer that option directly where file sharing is done, in that very dialog. +However I currently do not see any means to achieve that on ownCloud. There is +no feature offered to hook additional functionality into exsiting apps. +This means either the existing file sharing app has to be modified or such a +modifying core feature has to be implemented into the ownCLoud core. +Or maybe someone has got another idea ? + +* Integrated proxy function as an alternative to forwarding: +Currently all browser requests are forwarded to the final target url, provided +that the referenced shorty is still valid and accessible. This is a simple but +effective strategy. Offering a transparent proxy service as an alternative +would greatly enhance the privacy protection, since the final target url of a +referenced web ressource would never be handed out. + +* Better, more fine grained access control: +Currently the only means of access control, apart from defining or removing a +shorty are its "status". The status can block an otherwise valid shorty from +usage from outside ownCloud, it can restrict its access to authenticated users +or it can make an existing shorty freely accessible to the public. Other +ownCloud plugins allow to define individual access to content on per-user or +per-group rules. + +* Support of further backends: +Currently the usage of six url shortener services is implemented, besides the +two private or local ones. Unfortunately three of these had to be disabled due +to stability issues. Besides correcting the implementation for the disabled it +might make sense to support further backends, especially other types besides +online services. + +* Performance, stability and usability enhancements: +"Shorty" is my first web application using up to date web technologies. +Therefore the implementation certainly is far from the quality one could expect +from a serious and experienced web developer. One could also put this into more +constructive terms: there is definately much room for enhancements :-) + +* Translations of the shorty module itself (i18n/l10n): +Main development language is english (us), a german translation exists. I do +not feel fit enough in other languages to create a translation myself. So I +certainly welcome any assistance in that aspect. The effort consists of editing +one single file, take a look at the german example in file l10n/de.php. + +* Usage of svg icons instead of png graphics: +I created all icons in svg format. ownCloud implements a mechanism to use those +in browsers supporting svg directly. However I did not yet figure out how to +use that feature without adding too much scripting overhead. Is it possible +to reference icons the ownCloud way directly in a php based template, without +the need to explicit handling via javascript ? +I wish a better API documentation would exist for ownCloud ! + +* Localization for the date picker fields +Currently date inputs (expiration date) are not validated explicitly. +A number of formats work, are accepted correct, but there is no localization +of the input format to the users language. + +* Integrated help button +One thing I miss throughout the ownCloud application is a context sensitive +help, or a help button at all ! Originally I planned to integrate on into this +plugin. However I think that is more something that should be implemented as a +core feature of ownCloud. Maybe as a separate plugin (app). SOmehing like a +help framework with a documented api where other plugins (and core apps) can +attach help texts or documents to. Context sensivity would then simply mean to +update the reference in the help button for each action taken. + +Contributions: +I'd be more than happy to welcome all contributions to this little experiment. +Drop me a note, an idea, a patch, a good bottle of wine, anything ! diff --git a/apps/shorty/doc/STATUS b/apps/shorty/doc/STATUS new file mode 100644 index 00000000000..0b85d147028 --- /dev/null +++ b/apps/shorty/doc/STATUS @@ -0,0 +1,42 @@ +***** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +***** + +The current status of this package is as follows: + +The initial release is definately buggy and contains annoying shortcomings. +It has been developed on a linux system using a firefox browser, so this is +most likely the best working combination. Basic usage test have been made with +a few other browsers. The package appears to be working in general though there +might be some minor differences in apeparance. + +Known shortcomings are: +- only very basic input validation is done. +- access control is not yet fine grained, no user or group support exists. +- markup, scripting and style definitions are the work of a web app newbie. + +So "sorry for any inconveniences" ! + +Contributions: +I'd be more than happy to welcome all contributions to this little experiment. +Drop me a note, an idea, a patch, a good bottle of wine, anything ! diff --git a/apps/shorty/doc/USAGE b/apps/shorty/doc/USAGE new file mode 100644 index 00000000000..a82f881992a --- /dev/null +++ b/apps/shorty/doc/USAGE @@ -0,0 +1,64 @@ +***** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +***** + +=== Overview === +See file README. + +=== Installation === +See file INSTALLATION. + +=== Requirements === +ownCloud version 2 or newer on the server side. +A css3 capable and reasonably standards conform web browser. +A scripting capable bookmarks feature for the optional Shortlet thing. + +=== Usage === +This is only a very basic description. The plugin should be fairly intuitive to +use, just have a try with a few web urls. To get going I suggest that you +- chose a backend (see configuration below). +- import the shortlet into your preferred web browser (see configuration below). +- define a few shorties either manually ("New") or by using the shortlet. +All actions on existing shorties are accessed using the action icons shown to +the right of the shorty in the list. Daily uses is probably based on selection +the 'share' action and grabbing the visualized "source url". +By clicking on the header row of the list of shorties you can open (and close) +a "toolbox" offering options to sort, filter and reload the list. The sorting +you chose is stored in a persistant manner, not so any filters defined. You +cannot accidentially close the toolbox when there are still filters active. +You can remove (delete) existing shorties, but those shorties will only be +marked as deleted. This way you can 'undelete' them if required. Permanent +removal is done next time you access the shorty plugin. If you really want to +make sure the removal is done NOW then simply reload the list. This is done in +the "toolbox" of the list (click on the header row) by chosing the "reload" +icon on the left (or by a simple browser reload). + +=== PRIVACY === +Shorty allows you to stay more in control over links you post or send. It is up +to you to decide wether a once posted link should stay valid and usable or not. +However it is also very important to keep in mind that such form of control can +never replace any serious form of access control over the content published via +a published link. Shorty works as a short url resolver, meaning it forwards any +requesting web browser to the real address of the published content. This might +change when if future an integrated proxy function gets implemented, as opposed +to the current forwarding mechanism. diff --git a/apps/shorty/img/actions/down.png b/apps/shorty/img/actions/down.png Binary files differnew file mode 100644 index 00000000000..d2627e525ee --- /dev/null +++ b/apps/shorty/img/actions/down.png diff --git a/apps/shorty/img/actions/down.svg b/apps/shorty/img/actions/down.svg new file mode 100644 index 00000000000..b01642681c1 --- /dev/null +++ b/apps/shorty/img/actions/down.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.8pt" height="12.8pt"> +<defs/> +<g id="layer1"> + <path id="path3086" transform="matrix(0.000287724 1 -1 0.000287724 13.9983 1.99816)" fill="#000000" d="M2.22045e-15 0L12 6L0 12Z"/> + </g> +</svg> diff --git a/apps/shorty/img/actions/external.png b/apps/shorty/img/actions/external.png Binary files differnew file mode 100644 index 00000000000..5da1c41c45d --- /dev/null +++ b/apps/shorty/img/actions/external.png diff --git a/apps/shorty/img/actions/external.svg b/apps/shorty/img/actions/external.svg new file mode 100644 index 00000000000..32453b1ca29 --- /dev/null +++ b/apps/shorty/img/actions/external.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9.6pt" height="9.6pt"> +<defs/> +<g id="defitem0"> + <rect id="rect" transform="translate(1.5, 4.5)" fill="#ffffff" stroke="#585858" stroke-width="1.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4.00000000000" width="4.80000000000pt" height="4.80000000000pt"/> + <path id="arrow" transform="translate(2.75, 1)" fill="#303030" fill-rule="evenodd" d="M1.25 1.5L2.25 2.5L2.5 3.25L0 5.5L2.75 8.25L5 5.75L5.75 6L6.75 7L8.25 5.5L8.25 0L2.75 0Z"/> + <path id="gap" transform="translate(4, 2)" fill="#ffffff" fill-rule="evenodd" d="M2 0L6 0L6 4L5.5 4.75L4.25 2.75L1.25 6L0 4.75L3.25 1.75L1.25 0.5Z"/> + </g> +</svg> diff --git a/apps/shorty/img/actions/info.png b/apps/shorty/img/actions/info.png Binary files differnew file mode 100644 index 00000000000..2febafa33e5 --- /dev/null +++ b/apps/shorty/img/actions/info.png diff --git a/apps/shorty/img/actions/info.svg b/apps/shorty/img/actions/info.svg new file mode 100644 index 00000000000..e92ab4fbf0f --- /dev/null +++ b/apps/shorty/img/actions/info.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="595.277pt" + height="841.891pt" + id="svg2" + version="1.1" + inkscape:version="0.48.2 r9819" + sodipodi:docname="info.svg" + inkscape:export-filename="/srv/www/htdocs/owncloud/apps/shorty/img/actions/info.png" + inkscape:export-xdpi="1.4732735" + inkscape:export-ydpi="1.4732735"> + <metadata + id="metadata11"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="640" + inkscape:window-height="480" + id="namedview9" + showgrid="false" + inkscape:zoom="0.22425706" + inkscape:cx="372.0481" + inkscape:cy="526.18188" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:current-layer="svg2" /> + <defs + id="defs4" /> + <g + id="layer0" + transform="matrix(1,0,0,0.92242868,0,1.2000589)"> + <g + id="g4314" + transform="translate(212.946,163.839)" + style="fill:none"> + <path + id="path3536" + transform="translate(-61.9006,-148.543)" + d="m 0,487.048 c 12.4425,24.828 26.0633,44.836 51.6189,16.019 C 84.1849,485.573 192.482,410.026 184.704,480.779 155.218,612.203 117.891,742.51 90.9063,874.249 59.539,946.936 141.764,1009.03 222.092,959.781 308.42,926.996 381.595,875.821 456.598,828.62 445.035,807.645 436.536,777.24 408.795,806.094 371.289,821.672 291.128,891.94 272.933,836.765 298.192,694.682 351.067,556.912 382.294,415.755 414.151,350.273 353.103,270.879 270.187,326.914 169.549,367.14 86.8111,430.152 0,487.048 z M 357.158,0.174395 C 252.436,-0.955228 204.536,139.982 305.684,174.775 387.572,199.404 471.99,128.261 449.008,60.7166 441.179,25.4089 401.168,-2.47535 357.159,0.174395 z" + inkscape:connector-curvature="0" + style="fill:#000000" /> + </g> + </g> +</svg> diff --git a/apps/shorty/img/actions/left.png b/apps/shorty/img/actions/left.png Binary files differnew file mode 100644 index 00000000000..e76cf4df2ed --- /dev/null +++ b/apps/shorty/img/actions/left.png diff --git a/apps/shorty/img/actions/left.svg b/apps/shorty/img/actions/left.svg new file mode 100644 index 00000000000..670f0c3069a --- /dev/null +++ b/apps/shorty/img/actions/left.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.8pt" height="12.8pt"> +<defs/> +<g id="layer1"> + <path id="path3086" transform="matrix(-1 0 0 1 14 2)" fill="#000000" d="M0 0L12 6L0 12Z"/> + </g> +</svg> diff --git a/apps/shorty/img/actions/minus.png b/apps/shorty/img/actions/minus.png Binary files differnew file mode 100644 index 00000000000..72ee0f69ff2 --- /dev/null +++ b/apps/shorty/img/actions/minus.png diff --git a/apps/shorty/img/actions/open.png b/apps/shorty/img/actions/open.png Binary files differnew file mode 100644 index 00000000000..54cdd3a2a4c --- /dev/null +++ b/apps/shorty/img/actions/open.png diff --git a/apps/shorty/img/actions/open.svg b/apps/shorty/img/actions/open.svg new file mode 100644 index 00000000000..46e137d73f9 --- /dev/null +++ b/apps/shorty/img/actions/open.svg @@ -0,0 +1,10 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon14, part of koffice: http://www.koffice.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.8pt" height="12.8pt"> + <defs> + </defs> + <g id="layer1"> + <path id="path3086" fill="#000000" d="M9 14L5 14L4 7L0 7L7 0L14 7L10 7Z" transform="matrix(0.704343 0.70986 -0.70986 0.704343 8.03052 -1.90816)" /> + </g> +</svg> diff --git a/apps/shorty/img/actions/plus.png b/apps/shorty/img/actions/plus.png Binary files differnew file mode 100644 index 00000000000..f18d9c6c31a --- /dev/null +++ b/apps/shorty/img/actions/plus.png diff --git a/apps/shorty/img/actions/recycle.png b/apps/shorty/img/actions/recycle.png Binary files differnew file mode 100644 index 00000000000..29444fd7fd9 --- /dev/null +++ b/apps/shorty/img/actions/recycle.png diff --git a/apps/shorty/img/actions/recycle.svg b/apps/shorty/img/actions/recycle.svg new file mode 100644 index 00000000000..61ee3ac8409 --- /dev/null +++ b/apps/shorty/img/actions/recycle.svg @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="119.308pt" + height="121.472pt" + id="svg2" + version="1.1" + inkscape:version="0.48.2 r9819" + sodipodi:docname="recycle_arrows.svg"> + <title + id="title2987">recycle</title> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title>recycle</dc:title> + <cc:license + rdf:resource="http://creativecommons.org/licenses/by/3.0/" /> + <dc:date>2012</dc:date> + <dc:creator> + <cc:Agent> + <dc:title>Christian Reiner</dc:title> + </cc:Agent> + </dc:creator> + <dc:rights> + <cc:Agent> + <dc:title>Copyright 2012: Christian Reiner</dc:title> + </cc:Agent> + </dc:rights> + <dc:description>recycle</dc:description> + </cc:Work> + <cc:License + rdf:about="http://creativecommons.org/licenses/by/3.0/"> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Reproduction" /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Distribution" /> + <cc:requires + rdf:resource="http://creativecommons.org/ns#Notice" /> + <cc:requires + rdf:resource="http://creativecommons.org/ns#Attribution" /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> + </cc:License> + </rdf:RDF> + </metadata> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="965" + inkscape:window-height="679" + id="namedview8" + showgrid="false" + inkscape:zoom="1.5542677" + inkscape:cx="74.567497" + inkscape:cy="75.919998" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:current-layer="svg2" /> + <defs + id="defs4" /> + <g + id="layer0" + transform="matrix(-1,0,0,1,149.13468,0)" + inkscape:export-xdpi="9.6599998" + inkscape:export-ydpi="9.6599998" + inkscape:export-filename="/home/arkascha/Downloads/icons/recycle.png"> + <path + id="path1298" + d="M 70.8025,151.722 C 37.2549,149.448 11.1077,128.26 2.59247,96.4481 -1.14036,82.5027 -0.820931,65.3241 3.41386,52.2741 10.1512,31.5121 26.9843,13.3207 46.7093,5.48511 82.2059,-8.61567 120.257,5.14042 139.563,39.0531 c 7.34,12.8923 10.355,26.3175 9.4,41.853 -0.76,12.368 -2.629,19.5529 -7.945,30.5419 -3.422,7.074 -5.716,10.094 -13.664,18 -6.689,6.653 -11.649,10.604 -16.551,13.184 -12.0281,6.329 -27.8135,9.916 -40.0005,9.09 z m 4.5,-19.274 0.5,-7.481 5.5,-0.737 c 12.7535,-1.708 24.6295,-7.529 34.4625,-16.892 11.858,-11.2904 18.207,-24.78 19.251,-40.9052 0.739,-11.3966 -0.975,-20.6043 -5.72,-30.7354 C 122.022,20.167 104.421,6.43624 87.9323,3.42918 78.3665,1.68465 61.6527,2.66382 53.3025,5.45794 32.3445,12.4709 14.6307,28.9197 7.32185,48.1551 c -8.71433,22.9342 -5.7724,50.0896 7.63305,70.4559 4.2466,6.452 11.0409,13.477 12.0541,12.464 0.2731,-0.273 -1.1342,-3.139 -3.1273,-6.368 -6.2607,-10.143 -10.5792,-24.58 -10.5792,-35.3665 0,-5.978 2.4851,-18.5157 4.962,-25.0345 6.7044,-17.6444 24.9878,-32.6283 45.6647,-37.4235 3.7707,-0.8745 7.4223,-2.0601 8.1146,-2.6347 0.7686,-0.6379 1.2587,-3.5049 1.2587,-7.3632 0,-3.4751 0.4448,-6.5934 0.9885,-6.9294 1.3812,-0.85363 8.7657,2.5714 15.6814,7.2734 7.1284,4.8465 13.9516,12.0276 19.3896,20.4063 3.307,5.0959 3.997,6.944 3.578,9.5846 -1.425,8.9891 -17.7832,27.9223 -29.4402,34.0753 -3.4665,1.8297 -6.8857,3.1031 -7.5982,2.8297 -0.7624,-0.2926 -1.5662,-3.0878 -1.9535,-6.793 -0.3619,-3.4627 -1.0505,-6.6884 -1.5303,-7.1681 -1.2221,-1.2221 -9.6586,3.2474 -16.2231,8.5948 -9.0772,7.3942 -17.8922,20.3499 -17.8922,26.2968 0,9.067 14.0387,25.185 28.5,32.72 7.3326,3.821 7.9129,3.458 8.5,-5.327 z" + inkscape:connector-curvature="0" + style="fill:#010101" /> + </g> +</svg> diff --git a/apps/shorty/img/actions/reload.png b/apps/shorty/img/actions/reload.png Binary files differnew file mode 100644 index 00000000000..06df1f194e0 --- /dev/null +++ b/apps/shorty/img/actions/reload.png diff --git a/apps/shorty/img/actions/right.png b/apps/shorty/img/actions/right.png Binary files differnew file mode 100644 index 00000000000..a252a751554 --- /dev/null +++ b/apps/shorty/img/actions/right.png diff --git a/apps/shorty/img/actions/right.svg b/apps/shorty/img/actions/right.svg new file mode 100644 index 00000000000..997068063e3 --- /dev/null +++ b/apps/shorty/img/actions/right.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.8pt" height="12.8pt"> +<defs/> +<g id="layer1"> + <path id="path3086" transform="translate(2, 2)" fill="#000000" d="M0 0L12 6L0 12Z"/> + </g> +</svg> diff --git a/apps/shorty/img/actions/shade.png b/apps/shorty/img/actions/shade.png Binary files differnew file mode 100644 index 00000000000..a49b9ad34c4 --- /dev/null +++ b/apps/shorty/img/actions/shade.png diff --git a/apps/shorty/img/actions/shade.svg b/apps/shorty/img/actions/shade.svg new file mode 100644 index 00000000000..1823941c790 --- /dev/null +++ b/apps/shorty/img/actions/shade.svg @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="94.337173" + height="94.337173" + id="svg2" + version="1.1" + inkscape:version="0.48.2 r9819" + sodipodi:docname="up.svg"> + <metadata + id="metadata11"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="640" + inkscape:window-height="480" + id="namedview9" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:zoom="0.65555556" + inkscape:cx="76.57817" + inkscape:cy="35.476003" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:current-layer="svg2" /> + <defs + id="defs4" /> + <g + id="layer1" + transform="translate(-103.42183,-121.13883)"> + <path + id="shape0" + transform="translate(132.93,152.141)" + d="m 0,28.8704 35.4331,0 L 17.6016,0 z" + inkscape:connector-curvature="0" + style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.58899117;stroke-linecap:round;stroke-linejoin:round" /> + <circle + id="shape1" + transform="translate(106.299,124.016)" + r="44.291416" + cx="44.291416" + cy="44.291416" + stroke-miterlimit="2.00000000000" + sodipodi:cx="44.291416" + sodipodi:cy="44.291416" + sodipodi:rx="44.291416" + sodipodi:ry="44.291416" + style="fill:none;stroke:#000000;stroke-width:5.75434065;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:2" + d="m 88.582832,44.291416 c 0,24.461474 -19.829942,44.291416 -44.291416,44.291416 C 19.829942,88.582832 0,68.75289 0,44.291416 0,19.829942 19.829942,0 44.291416,0 68.75289,0 88.582832,19.829942 88.582832,44.291416 z" /> + </g> +</svg> diff --git a/apps/shorty/img/actions/up.png b/apps/shorty/img/actions/up.png Binary files differnew file mode 100644 index 00000000000..c878f84396c --- /dev/null +++ b/apps/shorty/img/actions/up.png diff --git a/apps/shorty/img/actions/up.svg b/apps/shorty/img/actions/up.svg new file mode 100644 index 00000000000..728243b3b5d --- /dev/null +++ b/apps/shorty/img/actions/up.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.8pt" height="12.8pt"> +<defs/> +<g id="layer1"> + <path id="path3086" transform="matrix(0.000287724 -1 -1 -0.000287724 13.9983 14.0016)" fill="#000000" d="M2.22045e-15 0L12 6L0 12Z"/> + </g> +</svg> diff --git a/apps/shorty/img/blank.png b/apps/shorty/img/blank.png Binary files differnew file mode 100644 index 00000000000..9386bf3e17b --- /dev/null +++ b/apps/shorty/img/blank.png diff --git a/apps/shorty/img/calendar.png b/apps/shorty/img/calendar.png Binary files differnew file mode 100644 index 00000000000..0e5fdb75bb6 --- /dev/null +++ b/apps/shorty/img/calendar.png diff --git a/apps/shorty/img/drag_me.png b/apps/shorty/img/drag_me.png Binary files differnew file mode 100644 index 00000000000..3ebac17d2d3 --- /dev/null +++ b/apps/shorty/img/drag_me.png diff --git a/apps/shorty/img/drag_me.svg b/apps/shorty/img/drag_me.svg new file mode 100644 index 00000000000..f1d44cdfb9d --- /dev/null +++ b/apps/shorty/img/drag_me.svg @@ -0,0 +1,135 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="595.277pt" height="841.891pt"> +<defs/> +<g id="Bubbles"> + <ellipse id="shape0" transform="translate(162.259, 571.542)" rx="20.11097874441pt" ry="8.61849622845pt" cx="20.11097874441pt" cy="8.61849622845pt" fill="none" stroke="#989898" stroke-width="3.45827370760" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000"/> + <path id="shape1" transform="translate(172.543, 536.388)" fill="none" stroke="#707071" stroke-width="3.45827370760" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" d="M63.9895 13.6082C63.9895 6.09258 49.6649 4.60196e-16 31.9947 0C14.3245 -4.60196e-16 2.16398e-15 6.09258 0 13.6082C-2.16398e-15 21.1237 14.3245 27.2163 31.9947 27.2163C49.6649 27.2163 63.9895 21.1237 63.9895 13.6082"/> + <path id="shape2" transform="translate(238.818, 495.564)" fill="none" stroke="#535353" stroke-width="3.45827370760" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" d="M254.815 38.5564C254.815 17.2623 197.773 1.30389e-15 127.408 0C57.0423 -1.30389e-15 8.61726e-15 17.2623 0 38.5564C-8.61726e-15 59.8506 57.0423 77.1129 127.408 77.1129C197.773 77.1129 254.815 59.8506 254.815 38.5564"/> + </g><g id="Text"> + <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2" baseProfile="tiny"> +<title>Qt Svg Document</title> +<desc>Generated with Qt</desc> +<defs> +</defs> +<g fill="none" stroke="black" stroke-width="1" fill-rule="evenodd" stroke-linecap="square" stroke-linejoin="bevel" > + +<g fill="none" stroke="none" transform="matrix(1,0,0,1,0,0)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1,0,0,1,-0.235294,-0.346925)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1,0,0,1,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="#1f1c1b" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="#1f1c1b" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="#1f1c1b" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="#333333" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +<text fill="#333333" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="33" font-family="Vahika" font-size="32" font-weight="700" font-style="normal" + >Drag</text> +<text fill="#333333" fill-opacity="1" stroke="none" xml:space="preserve" x="59.0156" y="33" font-family="Vahika" font-size="32" font-weight="700" font-style="normal" + > me !</text> +</g> + +<g fill="none" stroke="#1f1c1b" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="#1f1c1b" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,0,0)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="#1f1c1b" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="#1f1c1b" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1.25123,0,0,1.25123,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1,0,0,1,0,0)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1,0,0,1,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1,0,0,1,288,508.189)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1,0,0,1,-0.235294,-0.346925)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="none" transform="matrix(1,0,0,1,-0.235294,-0.346925)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> + +<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,0,0)" +font-family="Sans Serif" font-size="9" font-weight="400" font-style="normal" +> +</g> +</g> +</svg> + + </g> +</svg> diff --git a/apps/shorty/img/loading-bar.gif b/apps/shorty/img/loading-bar.gif Binary files differnew file mode 100644 index 00000000000..b02798a87eb --- /dev/null +++ b/apps/shorty/img/loading-bar.gif diff --git a/apps/shorty/img/loading-disk.gif b/apps/shorty/img/loading-disk.gif Binary files differnew file mode 100644 index 00000000000..22c961011cd --- /dev/null +++ b/apps/shorty/img/loading-disk.gif diff --git a/apps/shorty/img/loading-led.gif b/apps/shorty/img/loading-led.gif Binary files differnew file mode 100644 index 00000000000..78893c90606 --- /dev/null +++ b/apps/shorty/img/loading-led.gif diff --git a/apps/shorty/img/scheme/A.png b/apps/shorty/img/scheme/A.png Binary files differnew file mode 100644 index 00000000000..65163556bab --- /dev/null +++ b/apps/shorty/img/scheme/A.png diff --git a/apps/shorty/img/scheme/B.png b/apps/shorty/img/scheme/B.png Binary files differnew file mode 100644 index 00000000000..a5562488824 --- /dev/null +++ b/apps/shorty/img/scheme/B.png diff --git a/apps/shorty/img/scheme/C.png b/apps/shorty/img/scheme/C.png Binary files differnew file mode 100644 index 00000000000..61b873de73f --- /dev/null +++ b/apps/shorty/img/scheme/C.png diff --git a/apps/shorty/img/scheme/D.png b/apps/shorty/img/scheme/D.png Binary files differnew file mode 100644 index 00000000000..6ab7451d04a --- /dev/null +++ b/apps/shorty/img/scheme/D.png diff --git a/apps/shorty/img/scheme/E.png b/apps/shorty/img/scheme/E.png Binary files differnew file mode 100644 index 00000000000..d9c4e07001b --- /dev/null +++ b/apps/shorty/img/scheme/E.png diff --git a/apps/shorty/img/scheme/F.png b/apps/shorty/img/scheme/F.png Binary files differnew file mode 100644 index 00000000000..2663b5eb308 --- /dev/null +++ b/apps/shorty/img/scheme/F.png diff --git a/apps/shorty/img/scheme/G.png b/apps/shorty/img/scheme/G.png Binary files differnew file mode 100644 index 00000000000..d1d965d34cb --- /dev/null +++ b/apps/shorty/img/scheme/G.png diff --git a/apps/shorty/img/scheme/H.png b/apps/shorty/img/scheme/H.png Binary files differnew file mode 100644 index 00000000000..c644a77bfc5 --- /dev/null +++ b/apps/shorty/img/scheme/H.png diff --git a/apps/shorty/img/scheme/J.png b/apps/shorty/img/scheme/J.png Binary files differnew file mode 100644 index 00000000000..0eaa189f4f6 --- /dev/null +++ b/apps/shorty/img/scheme/J.png diff --git a/apps/shorty/img/scheme/K.png b/apps/shorty/img/scheme/K.png Binary files differnew file mode 100644 index 00000000000..3d587ae4478 --- /dev/null +++ b/apps/shorty/img/scheme/K.png diff --git a/apps/shorty/img/scheme/L.png b/apps/shorty/img/scheme/L.png Binary files differnew file mode 100644 index 00000000000..4e37b9f3645 --- /dev/null +++ b/apps/shorty/img/scheme/L.png diff --git a/apps/shorty/img/scheme/M.png b/apps/shorty/img/scheme/M.png Binary files differnew file mode 100644 index 00000000000..a4a02e60b40 --- /dev/null +++ b/apps/shorty/img/scheme/M.png diff --git a/apps/shorty/img/scheme/N.png b/apps/shorty/img/scheme/N.png Binary files differnew file mode 100644 index 00000000000..6c860f77347 --- /dev/null +++ b/apps/shorty/img/scheme/N.png diff --git a/apps/shorty/img/scheme/O.png b/apps/shorty/img/scheme/O.png Binary files differnew file mode 100644 index 00000000000..14a05847b5c --- /dev/null +++ b/apps/shorty/img/scheme/O.png diff --git a/apps/shorty/img/scheme/P.png b/apps/shorty/img/scheme/P.png Binary files differnew file mode 100644 index 00000000000..e53d3ee9801 --- /dev/null +++ b/apps/shorty/img/scheme/P.png diff --git a/apps/shorty/img/scheme/Q.png b/apps/shorty/img/scheme/Q.png Binary files differnew file mode 100644 index 00000000000..d07c42a76de --- /dev/null +++ b/apps/shorty/img/scheme/Q.png diff --git a/apps/shorty/img/scheme/R.png b/apps/shorty/img/scheme/R.png Binary files differnew file mode 100644 index 00000000000..9b522d6c5a0 --- /dev/null +++ b/apps/shorty/img/scheme/R.png diff --git a/apps/shorty/img/scheme/S.png b/apps/shorty/img/scheme/S.png Binary files differnew file mode 100644 index 00000000000..1aff52f7525 --- /dev/null +++ b/apps/shorty/img/scheme/S.png diff --git a/apps/shorty/img/scheme/T.png b/apps/shorty/img/scheme/T.png Binary files differnew file mode 100644 index 00000000000..1736eedc47b --- /dev/null +++ b/apps/shorty/img/scheme/T.png diff --git a/apps/shorty/img/scheme/U.png b/apps/shorty/img/scheme/U.png Binary files differnew file mode 100644 index 00000000000..320938cedf1 --- /dev/null +++ b/apps/shorty/img/scheme/U.png diff --git a/apps/shorty/img/scheme/V.png b/apps/shorty/img/scheme/V.png Binary files differnew file mode 100644 index 00000000000..2fe5e5a1621 --- /dev/null +++ b/apps/shorty/img/scheme/V.png diff --git a/apps/shorty/img/scheme/W.png b/apps/shorty/img/scheme/W.png Binary files differnew file mode 100644 index 00000000000..e7b37b011f2 --- /dev/null +++ b/apps/shorty/img/scheme/W.png diff --git a/apps/shorty/img/scheme/X.png b/apps/shorty/img/scheme/X.png Binary files differnew file mode 100644 index 00000000000..4a3d8bd3816 --- /dev/null +++ b/apps/shorty/img/scheme/X.png diff --git a/apps/shorty/img/scheme/Y.png b/apps/shorty/img/scheme/Y.png Binary files differnew file mode 100644 index 00000000000..af76045e897 --- /dev/null +++ b/apps/shorty/img/scheme/Y.png diff --git a/apps/shorty/img/scheme/Z.png b/apps/shorty/img/scheme/Z.png Binary files differnew file mode 100644 index 00000000000..0d00ced9c14 --- /dev/null +++ b/apps/shorty/img/scheme/Z.png diff --git a/apps/shorty/img/shorty.png b/apps/shorty/img/shorty.png Binary files differnew file mode 100644 index 00000000000..3fa8a55f9d8 --- /dev/null +++ b/apps/shorty/img/shorty.png diff --git a/apps/shorty/img/shorty.svg b/apps/shorty/img/shorty.svg new file mode 100644 index 00000000000..79b2ee69015 --- /dev/null +++ b/apps/shorty/img/shorty.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.8pt" height="12.8pt"> +<defs/> +<g id="g4185"> + <path id="path4189" transform="translate(-0.0314065, 3.97605)" fill="#d3d3d3" d="M5.90496 5.36366e-05L2.03624 0.0483836C0.896812 0.0603836 -0.00985361 2.07369 8.08645e-05 4.5713C0.0100142 7.06891 0.928138 9.07722 2.06757 9.06522L5.93628 9.01689C6.91266 9.00662 7.71351 7.51489 7.91762 5.5184L8.09775 5.5184C8.29805 7.56949 9.13062 9.09502 10.1261 9.08454L13.9948 9.04589C15.1342 9.03389 16.0409 7.01093 16.031 4.51331C16.021 2.0157 15.1029 0.0170616 13.9635 0.0290566L10.0869 0.0677066C9.14538 0.0776066 8.36671 1.46464 8.12907 3.35358L7.90196 3.35358C7.66674 1.41099 6.86557 -0.0100594 5.90496 5.36366e-05ZM4.99651 1.48836C5.86074 1.48036 6.59686 2.24823 6.90737 3.35358L4.47181 3.35358C4.19414 3.35358 3.9706 3.83634 3.9706 4.43599C3.9706 5.03564 4.19414 5.5184 4.47181 5.5184L6.95436 5.5184C6.67695 6.7007 5.92436 7.54932 5.02784 7.55758L2.99951 7.57691C1.86007 7.58743 0.931832 6.24436 0.924186 4.56163C0.916536 2.8789 1.82875 1.50853 2.96818 1.49803L4.99651 1.48843ZM13.055 1.51735C14.1945 1.50686 15.1149 2.84023 15.1225 4.52297C15.1301 6.2057 14.218 7.57607 13.0785 7.58656L11.0502 7.59616C10.1318 7.60466 9.35598 6.73612 9.0845 5.51833L11.4887 5.51833C11.7664 5.51833 11.99 5.03557 11.99 4.43592C11.99 3.83627 11.7664 3.35351 11.4887 3.35351L9.15499 3.35351C9.46901 2.2831 10.1849 1.53477 11.0267 1.52702L13.055 1.51742Z"/> + </g><g id="g4849"> + <path id="path4851" transform="translate(-8.08646e-05, 2.9323)" fill="#505053" fill-opacity="0.95294117647" d="M5.90496 5.36369e-05L2.03624 0.0483836C0.896812 0.0603756 -0.00985362 2.07368 8.08646e-05 4.5713C0.0100142 7.06891 0.928138 9.07721 2.06757 9.06522L5.93628 9.01689C6.91266 9.00662 7.71351 7.51488 7.91762 5.51839L8.09775 5.51839C8.29805 7.56948 9.13062 9.09502 10.1261 9.08454L13.9948 9.04589C15.1342 9.03389 16.0409 7.01092 16.031 4.51331C16.0211 2.01569 15.1029 0.0170526 13.9635 0.0290466L10.0869 0.0676976C9.14538 0.0775976 8.36671 1.46464 8.12907 3.35358L7.90196 3.35358C7.66674 1.41098 6.86557 -0.0100594 5.90496 5.36369e-05ZM4.99651 1.48836C5.86074 1.48036 6.59686 2.24823 6.90737 3.35358L4.47181 3.35358C4.19414 3.35358 3.9706 3.83634 3.9706 4.43599C3.9706 5.03564 4.19414 5.5184 4.47181 5.5184L6.95436 5.5184C6.67695 6.7007 5.92436 7.54931 5.02784 7.55758L2.99951 7.5769C1.86007 7.5874 0.931832 6.24436 0.924186 4.56162C0.91654 2.87889 1.82875 1.50853 2.96818 1.49803L4.99651 1.48843ZM13.055 1.51735C14.1945 1.50686 15.1149 2.84024 15.1225 4.52297C15.1301 6.2057 14.218 7.57607 13.0785 7.58657L11.0502 7.59617C10.1318 7.60467 9.35598 6.73612 9.0845 5.51833L11.4887 5.51833C11.7664 5.51833 11.99 5.03558 11.99 4.43592C11.99 3.83627 11.7664 3.35352 11.4887 3.35352L9.15499 3.35352C9.46901 2.28304 10.1849 1.53471 11.0267 1.52695Z"/> + </g> +</svg> diff --git a/apps/shorty/img/status/active.png b/apps/shorty/img/status/active.png Binary files differnew file mode 100644 index 00000000000..51d013cd058 --- /dev/null +++ b/apps/shorty/img/status/active.png diff --git a/apps/shorty/img/status/active.svg b/apps/shorty/img/status/active.svg new file mode 100644 index 00000000000..bb4c0573af1 --- /dev/null +++ b/apps/shorty/img/status/active.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="75.4697pt" height="75.4697pt"> +<defs/> +<g id="layer1"> + <circle id="shape1" transform="translate(2.87717, 2.87717)" r="35.43313280000pt" cx="35.43313280000pt" cy="35.43313280000pt" fill="none" stroke="#000000" stroke-width="5.75434065000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000"/> + </g> +</svg> diff --git a/apps/shorty/img/status/bad.png b/apps/shorty/img/status/bad.png Binary files differnew file mode 100644 index 00000000000..11627a21fee --- /dev/null +++ b/apps/shorty/img/status/bad.png diff --git a/apps/shorty/img/status/good.png b/apps/shorty/img/status/good.png Binary files differnew file mode 100644 index 00000000000..08ce0a4453a --- /dev/null +++ b/apps/shorty/img/status/good.png diff --git a/apps/shorty/img/status/neutral.png b/apps/shorty/img/status/neutral.png Binary files differnew file mode 100644 index 00000000000..5b2ad589cb9 --- /dev/null +++ b/apps/shorty/img/status/neutral.png diff --git a/apps/shorty/img/status/strike.png b/apps/shorty/img/status/strike.png Binary files differnew file mode 100644 index 00000000000..d9a867fa004 --- /dev/null +++ b/apps/shorty/img/status/strike.png diff --git a/apps/shorty/img/usage/64/arrow.png b/apps/shorty/img/usage/64/arrow.png Binary files differnew file mode 100644 index 00000000000..ac35f78ad1c --- /dev/null +++ b/apps/shorty/img/usage/64/arrow.png diff --git a/apps/shorty/img/usage/64/clipboard.png b/apps/shorty/img/usage/64/clipboard.png Binary files differnew file mode 100644 index 00000000000..701bb6a7796 --- /dev/null +++ b/apps/shorty/img/usage/64/clipboard.png diff --git a/apps/shorty/img/usage/64/email.png b/apps/shorty/img/usage/64/email.png Binary files differnew file mode 100644 index 00000000000..cfa1f767821 --- /dev/null +++ b/apps/shorty/img/usage/64/email.png diff --git a/apps/shorty/img/usage/64/globe.png b/apps/shorty/img/usage/64/globe.png Binary files differnew file mode 100644 index 00000000000..2d41da4819a --- /dev/null +++ b/apps/shorty/img/usage/64/globe.png diff --git a/apps/shorty/img/usage/64/home.png b/apps/shorty/img/usage/64/home.png Binary files differnew file mode 100644 index 00000000000..8cff03b28c6 --- /dev/null +++ b/apps/shorty/img/usage/64/home.png diff --git a/apps/shorty/img/usage/64/info.png b/apps/shorty/img/usage/64/info.png Binary files differnew file mode 100644 index 00000000000..2069088f64a --- /dev/null +++ b/apps/shorty/img/usage/64/info.png diff --git a/apps/shorty/img/usage/64/locked.png b/apps/shorty/img/usage/64/locked.png Binary files differnew file mode 100644 index 00000000000..841d2d4483f --- /dev/null +++ b/apps/shorty/img/usage/64/locked.png diff --git a/apps/shorty/img/usage/64/network.png b/apps/shorty/img/usage/64/network.png Binary files differnew file mode 100644 index 00000000000..fac47ac7b75 --- /dev/null +++ b/apps/shorty/img/usage/64/network.png diff --git a/apps/shorty/img/usage/64/qrcode.png b/apps/shorty/img/usage/64/qrcode.png Binary files differnew file mode 100644 index 00000000000..207741888d3 --- /dev/null +++ b/apps/shorty/img/usage/64/qrcode.png diff --git a/apps/shorty/img/usage/64/sms.png b/apps/shorty/img/usage/64/sms.png Binary files differnew file mode 100644 index 00000000000..5dcd2c12231 --- /dev/null +++ b/apps/shorty/img/usage/64/sms.png diff --git a/apps/shorty/img/usage/64/team.png b/apps/shorty/img/usage/64/team.png Binary files differnew file mode 100644 index 00000000000..e6ea3375807 --- /dev/null +++ b/apps/shorty/img/usage/64/team.png diff --git a/apps/shorty/img/usage/64/unlocked.png b/apps/shorty/img/usage/64/unlocked.png Binary files differnew file mode 100644 index 00000000000..54501bbd11f --- /dev/null +++ b/apps/shorty/img/usage/64/unlocked.png diff --git a/apps/shorty/img/usage/64/workstation.png b/apps/shorty/img/usage/64/workstation.png Binary files differnew file mode 100644 index 00000000000..909098c9d8d --- /dev/null +++ b/apps/shorty/img/usage/64/workstation.png diff --git a/apps/shorty/img/usage/_.svg b/apps/shorty/img/usage/_.svg new file mode 100644 index 00000000000..e0ef15d83c3 --- /dev/null +++ b/apps/shorty/img/usage/_.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062897958" y1="-2.28811738018" x2="1.88918016404" y2="-1.09199169808" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5381" transform="translate(-5.94477e-06, 2.56921e-06)" fill="none"> + <path id="path4167" transform="matrix(0.758527 0 0 0.768105 -8.17197e-15 -3.02746e-16)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4169" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47751)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="text4182" transform="translate(66.8213, 30.5499)" fill="none"/> + <path id="path4171" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46647)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/arrow.svg b/apps/shorty/img/usage/arrow.svg new file mode 100644 index 00000000000..94b2bf96abe --- /dev/null +++ b/apps/shorty/img/usage/arrow.svg @@ -0,0 +1,22 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062897958" y1="-2.28811738018" x2="1.88918016404" y2="-1.09199169808" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5327" transform="translate(5.00882e-07, -1.00277e-06)" fill="none"> + <path id="path4155" transform="matrix(0.758527 0 0 0.768105 -6.61744e-23 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4157" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47751)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="g4149" transform="translate(32.6557, 32.5571)" fill="none"> + <path id="path4138" transform="matrix(-0.168373 -0.438415 0.36134 -0.202146 27.838 126.426)" fill="#eeeeee" d="M160.243 0.00621995C156.111 0.109866 152.106 1.44866 148.743 3.84997L8.68012 103.631C2.66423 107.918 -0.608526 115.089 0.0939771 122.442C0.79648 129.796 5.36759 136.217 12.0864 139.287L168.524 210.694C175.246 213.766 183.097 213.018 189.118 208.731C195.139 204.444 198.415 197.27 197.711 189.912L181.336 18.725C180.308 7.91607 171.097 -0.257837 160.243 0.00621995Z"/> + <rect id="rect4143" transform="matrix(0.624447 0 0 0.610576 81.3708 26.8172)" fill="#eeeeee" width="16.29353760000pt" height="62.66744960000pt" rx="8.14676880000pt" ry="15.60399600000pt"/> + </g> + <path id="path4159" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46647)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/clipboard.svg b/apps/shorty/img/usage/clipboard.svg new file mode 100644 index 00000000000..a470bdaae45 --- /dev/null +++ b/apps/shorty/img/usage/clipboard.svg @@ -0,0 +1,34 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062897958" y1="-2.28811738018" x2="1.88918016404" y2="-1.09199169808" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5381" transform="translate(-5.94477e-06, 2.56921e-06)" fill="none"> + <path id="path4167" transform="matrix(0.758527 0 0 0.768105 -8.17197e-15 -3.02746e-16)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4169" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47751)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="text4182" transform="translate(66.8213, 30.5499)" fill="none"/> + <path id="path4171" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46647)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + <g id="g4549" transform="translate(42.322, 7.02379)" fill="none"> + <g id="g4542" transform="translate(-3.5, 49.2276)" fill="none"> + <rect id="rect812" transform="translate(3.5, 3.5)" fill="none" stroke="#ffffff" stroke-width="7.00000000000" stroke-linecap="butt" stroke-linejoin="round" width="52.59049680000pt" height="52.21751680000pt" rx="2.07274704000pt" ry="2.07274704000pt"/> + <path id="path842" transform="translate(10.9597, 16.8727)" fill="none" stroke="#ffffff" stroke-width="7.00000000000" stroke-linecap="round" stroke-linejoin="round" d="M0 0L49.8864 0"/> + <path id="path845" transform="translate(10.9597, 29.7461)" fill="none" stroke="#ffffff" stroke-width="7.00000000000" stroke-linecap="round" stroke-linejoin="round" d="M0 0L49.8864 0"/> + <path id="path846" transform="translate(10.9597, 42.6194)" fill="none" stroke="#ffffff" stroke-width="7.00000000000" stroke-linecap="round" stroke-linejoin="round" d="M0 0L49.8864 0"/> + <path id="path848" transform="translate(10.8847, 55.4927)" fill="none" stroke="#ffffff" stroke-width="7.00000000000" stroke-linecap="round" stroke-linejoin="round" d="M0 0L27.6572 0"/> + </g> + <g id="g886" transform="translate(24.5258, 32.1333)" fill="none"> + <path id="path599" transform="translate(1.56892, 48.6283)" fill="#ffffff" stroke="#b3b3b3" stroke-width="3.13784003000" stroke-linecap="round" stroke-linejoin="round" d="M16.3475 5.47447C0 17.0594 0 17.0594 0 17.0594L10.0728 0Z"/> + <rect id="rect598" transform="matrix(-0.911191 -0.824059 0.824059 -0.911191 17.3856 54.0244)" fill="#ffffff" stroke="#b3b3b3" stroke-width="3.13783836000" stroke-linecap="round" stroke-linejoin="round" width="5.23702200000pt" height="37.70656160000pt"/> + <path id="path600" transform="translate(4.47967, 60.1754)" fill="#ffffff" stroke="#b3b3b3" stroke-width="2.31749964000" stroke-linecap="butt" stroke-linejoin="round" d="M0.264548 0.337176C0.643913 -0.0822999 1.2915 -0.114817 1.71098 0.264548C2.13045 0.643913 2.16297 1.2915 1.7836 1.71098C1.40424 2.13045 0.756651 2.16297 0.337175 1.7836C-0.0823005 1.40424 -0.114816 0.756651 0.264548 0.337176Z"/> + <rect id="rect601" transform="matrix(-0.911191 -0.824059 0.824059 -0.911191 56.463 11.5345)" fill="#ffffff" stroke="#b3b3b3" stroke-width="3.13783836000" stroke-linecap="butt" stroke-linejoin="round" width="5.97020528000pt" height="3.24695360000pt" rx="1.64633232000pt" ry="1.62347680000pt"/> + </g> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/email.svg b/apps/shorty/img/usage/email.svg new file mode 100644 index 00000000000..7283939e37a --- /dev/null +++ b/apps/shorty/img/usage/email.svg @@ -0,0 +1,21 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062868749" y1="-2.28811738018" x2="1.88917986746" y2="-1.09199169808" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5473" transform="translate(1.28609e-06, 3.64259e-06)" fill="none"> + <path id="path5063" transform="matrix(0.758527 0 0 0.768105 -2.64698e-22 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path5065" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47751)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="text5197" transform="translate(30.5827, 32.9153)" fill="none"> + <path id="path5202" transform="matrix(0.794213 0 0 0.724445 -1.42109e-13 4.44089e-15)" fill="#eeeeee" d="M80.7728 37.0436L82.4783 29.4711L100.488 29.4711L90.119 78.3851C89.4822 81.4778 89.1638 83.5244 89.1639 84.5249C89.1638 85.571 89.4139 86.3896 89.9143 86.9808C90.46 87.5721 91.0967 87.8677 91.8245 87.8677C94.2803 87.8677 97.4412 86.2759 101.307 83.0923C105.218 79.8632 108.607 75.4971 111.472 69.994C114.382 64.4454 115.838 58.3966 115.838 51.8474C115.838 46.3898 114.792 41.2506 112.7 36.4296C110.653 31.6088 107.674 27.4246 103.763 23.8771C99.8516 20.3297 95.008 17.5554 89.2321 15.5542C83.5015 13.5532 76.9979 12.5526 69.7211 12.5525C62.3078 12.5526 55.5085 13.5304 49.3233 15.486C43.1379 17.3962 37.703 20.1705 33.0186 23.8089C28.3341 27.4019 24.4228 31.8589 21.2847 37.18C18.5104 41.8191 16.3956 46.9583 14.9402 52.5978C13.4849 58.2374 12.7572 63.9906 12.7572 69.8575C12.7572 77.6802 14.3035 84.8433 17.3962 91.3469C20.5343 97.8051 25.0596 103.217 30.972 107.583C36.9299 111.995 44.1157 115.11 52.5296 116.93C60.9434 118.794 70.4487 119.181 81.0457 118.089C89.4594 117.089 96.5771 115.179 102.399 112.359C108.265 109.539 113.223 105.582 117.271 100.488L131.802 100.488C129.436 105.355 126.344 109.698 122.524 113.519C118.749 117.339 114.314 120.545 109.221 123.138C104.127 125.775 98.419 127.777 92.0974 129.141C85.7755 130.505 78.8853 131.188 71.4266 131.188C60.2384 131.188 50.1646 129.709 41.205 126.753C32.2454 123.843 24.6957 119.613 18.5559 114.064C12.4616 108.561 7.84532 101.989 4.7072 94.3486C1.56906 86.6625 -9.99995e-06 78.1805 4.79758e-11 68.9025C-9.99995e-06 59.2152 1.61454 50.1647 4.84364 41.7508C8.07272 33.337 12.7117 26.0375 18.7606 19.8521C24.8549 13.6214 32.2682 8.75503 41.0004 5.25296C49.778 1.75109 59.4425 0.0001 69.994 0C78.6352 0.0001 86.5487 1.27355 93.7347 3.82034C100.966 6.32184 107.151 9.93751 112.291 14.6674C117.43 19.3974 121.341 25.0142 124.024 31.5178C126.753 37.976 128.117 45.1164 128.118 52.9389C128.117 59.0333 127.026 65.0139 124.843 70.8809C122.66 76.7023 119.522 81.9553 115.429 86.6397C111.381 91.2787 106.605 94.9626 101.102 97.6914C95.5992 100.375 89.6641 101.716 83.297 101.716C79.613 101.716 76.7477 101.102 74.7012 99.8745C72.6545 98.601 71.2901 96.5999 70.608 93.8711C66.6511 97.7824 62.1031 100.261 56.9639 101.307C51.8246 102.308 46.8445 101.83 42.0237 99.8745C37.2027 97.8733 33.2915 94.5305 30.2898 89.8461C27.3336 85.1616 25.8555 79.3857 25.8555 72.5181C25.8555 65.3778 27.379 58.3511 30.4262 51.4381C33.5189 44.5251 37.8849 38.8629 43.5245 34.4512C49.2095 30.0397 55.6222 27.8339 62.7627 27.8339C70.949 27.8339 76.9524 30.9038 80.7728 37.0436M43.4563 72.3817C43.4563 77.8393 44.5933 82.0235 46.8673 84.9342C49.1413 87.845 52.1202 89.3003 55.8042 89.3003C60.0793 89.3003 63.8314 87.5948 67.0605 84.1838C70.335 80.7728 72.8137 76.4749 74.4965 71.2902C76.1792 66.06 77.0206 61.0117 77.0207 56.1453C77.0206 53.7349 76.725 51.5746 76.1338 49.6643C75.588 47.7088 74.7466 46.0032 73.6097 44.5478C72.5181 43.0925 71.1764 42.001 69.5847 41.2733C68.0383 40.5002 66.2646 40.1136 64.2635 40.1135C60.2612 40.1136 56.6455 41.6826 53.4165 44.8207C50.2328 47.9134 47.7769 51.9611 46.0487 56.9639C44.3204 61.9213 43.4563 67.0606 43.4563 72.3817"/> + </g> + <path id="path5067" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46647)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/globe.svg b/apps/shorty/img/usage/globe.svg new file mode 100644 index 00000000000..018f161dbf4 --- /dev/null +++ b/apps/shorty/img/usage/globe.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062897958" y1="-2.28811733465" x2="1.88918016404" y2="-1.09199167635" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5362" transform="translate(-3.40191e-06, 5.08678e-06)" fill="none"> + <path id="path4239" transform="matrix(0.758527 0 0 0.768105 5.29396e-22 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4241" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47748)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path244" transform="matrix(0.758527 0 0 0.758527 23.1973 27.4649)" fill="#eeeeee" d="M80.5927 0.0948932C60.0949 -0.911807 40.4347 6.11839 25.2406 19.8968C10.0239 33.6889 1.10091 52.5655 0.0948972 73.0487C-0.911853 93.5465 6.11847 113.207 19.9112 128.409C33.6819 143.61 52.5585 152.533 73.0563 153.54C115.377 155.618 151.469 122.891 153.547 80.5855C155.625 38.2798 122.913 2.17339 80.5927 0.0948932ZM141.304 79.9841C140.952 87.1558 139.42 93.9908 136.945 100.317C131.792 99.6461 126.706 98.7947 121.689 97.7487C126.836 85.2521 128.594 71.5547 126.644 57.7998C124.785 44.717 119.689 32.8544 112.313 22.9264C130.73 35.0912 142.463 56.3835 141.304 79.9841ZM92.0321 26.1704C79.4068 40.6691 68.6314 56.7845 60.0807 74.2049C52.8482 70.0132 45.8857 65.4019 39.2203 60.4163C44.6575 50.0833 52.8087 41.3948 63.0583 35.2373C72.1673 29.7501 82.0974 26.8121 92.0321 26.1704ZM54.9821 85.4129C49.529 98.3126 45.2546 111.857 42.3271 125.908C41.8765 125.226 41.4339 124.529 41.0136 123.826C32.1223 109.048 29.5275 91.6818 33.686 74.9699C33.9167 74.0056 34.1893 73.0873 34.4639 72.1252C41.0431 76.9231 47.8895 81.3601 54.9821 85.4129ZM59.6738 132.526C57.583 132.827 55.4987 132.996 53.4253 133.092C56.1068 118.523 60.2937 104.519 65.8325 91.2201C77.7539 97.1755 90.2767 102.089 103.311 105.84C102.95 106.335 102.586 106.868 102.209 107.377C91.8412 121.166 76.7464 130.085 59.6738 132.526ZM70.8853 80.0467C79.4919 62.3869 90.5152 46.1516 103.52 31.6862C109.148 39.7311 113.028 49.1426 114.5 59.5069C116.233 71.7252 114.484 83.8752 109.573 94.8576C96.0784 91.2018 83.1341 86.2087 70.8853 80.0467ZM33.472 28.994C46.248 17.4001 62.7647 11.4919 79.9914 12.338C83.8846 12.5292 87.6863 13.0901 91.3568 13.9305C79.4801 14.6823 67.6153 18.1782 56.7378 24.723C45.2255 31.6472 35.9361 41.2556 29.501 52.6399C26.5147 50.1165 23.5977 47.5232 20.7443 44.8302C24.0834 38.9789 28.3438 33.6351 33.472 28.994ZM12.3453 73.6503C12.6332 67.7886 13.7123 62.0978 15.4974 56.669C18.3272 59.2435 21.2192 61.7475 24.1803 64.1891C23.2561 66.7258 22.4531 69.3346 21.7789 72.0084C18.4881 85.2417 18.776 98.7975 22.4326 111.573C15.2371 100.355 11.6786 87.2253 12.3453 73.6503ZM75.343 141.335C89.8738 136.43 102.603 127.284 112.015 114.74C113.396 112.9 114.692 111.006 115.896 109.055C120.881 110.158 125.911 111.094 131.015 111.873C119.175 130.1 98.4601 141.884 75.343 141.335Z"/> + <path id="path4243" transform="matrix(0.758527 0 0 0.758527 5.33865 4.46648)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 -1.13687e-13 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/home.svg b/apps/shorty/img/usage/home.svg new file mode 100644 index 00000000000..8c29644503c --- /dev/null +++ b/apps/shorty/img/usage/home.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062897958" y1="-2.28811738018" x2="1.88918016404" y2="-1.09199169808" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5314" transform="translate(-8.17503e-06, -2.94544e-06)" fill="none"> + <path id="path4087" transform="matrix(0.758527 0 0 0.768105 1.05879e-21 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4089" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47751)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="g4126" transform="translate(27.3419, 27.8174)" fill="none"> + <path id="path4109" transform="matrix(0.646168 0 0 0.646168 2.22045e-14 1.77636e-14)" fill="#eeeeee" d="M83.9733 0.0146219C81.7822 0.0969449 79.6354 0.511418 77.6608 1.23337C74.7217 2.30249 72.2731 4.0111 70.6295 6.13962L2.22329 94.9209C-0.141455 97.987 -0.646597 101.673 0.836575 105.04C2.31975 108.407 5.648 111.13 9.97329 112.515L71.4108 32.7959C73.0479 30.6558 75.4972 28.9358 78.442 27.8584C86.1818 25.036 95.4931 27.2205 99.7545 32.8584L160.005 112.39C163.905 110.818 166.796 108.12 168.021 104.912C169.245 101.704 168.698 98.2572 166.505 95.3584L98.9733 6.23337C95.9221 2.19242 90.1245 -0.211173 83.9733 0.0146219Z"/> + <path id="rect4116" transform="matrix(0.646168 0 0 0.646168 20.0253 26.3303)" fill="#eeeeee" d="M52.6562 0.00858529C51.3133 0.0537124 49.9957 0.308743 48.7812 0.758585C46.9652 1.43702 45.452 2.5257 44.4375 3.88359L2.4062 60.2898C2.26096 60.4729 2.12543 60.6606 1.99995 60.8523C1.98995 60.8666 2.00995 60.9004 1.99995 60.9148C1.96841 60.9459 1.93718 60.9771 1.90625 61.0085C0.67894 62.8827 0 65.1221 0 67.5398L0 116.571C0 123.169 5.28309 128.477 11.875 128.477L36.4375 128.477L36.4375 85.571C36.4375 78.9733 41.7206 73.6648 48.3125 73.6648L57.4375 73.6648C64.0294 73.6648 69.3125 78.9733 69.3125 85.571L69.3125 128.477L93.8437 128.477C100.436 128.477 105.75 123.169 105.75 116.571L105.75 67.5398C105.75 64.4233 104.538 61.6268 102.594 59.5085L61.8437 3.94604C59.9691 1.39179 56.4219 -0.128436 52.6562 0.00853529Z"/> + <rect id="rect4124" transform="matrix(0.646168 0 0 0.646168 21.5365 9.64032)" fill="#eeeeee" width="18.17356080000pt" height="31.33372480000pt" rx="9.08678040000pt" ry="14.74450800000pt"/> + </g> + <path id="path4091" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46647)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/info.svg b/apps/shorty/img/usage/info.svg new file mode 100644 index 00000000000..31a3b6387eb --- /dev/null +++ b/apps/shorty/img/usage/info.svg @@ -0,0 +1,21 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062897958" y1="-2.28811738018" x2="1.88918016404" y2="-1.09199169808" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5381" transform="translate(-5.94477e-06, 2.56921e-06)" fill="none"> + <path id="path4167" transform="matrix(0.758527 0 0 0.768105 0 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4169" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47751)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="text4182" transform="translate(66.8213, 30.5499)" fill="none"> + <path id="path4187" transform="matrix(1.54651 0 0 0.965127 -2.30926e-13 8.88178e-15)" fill="#eeeeee" d="M19.1953 38.6016L19.1953 94.0781C19.1953 97.9219 18.2812 100.828 16.4531 102.797C14.625 104.766 12.3047 105.75 9.49218 105.75C6.67967 105.75 4.38279 104.742 2.60156 102.727C0.86717 100.711 -9.99991e-06 97.8281 8.66294e-11 94.0781L8.66294e-11 39.1641C-9.99991e-06 35.3673 0.86717 32.5079 2.60156 30.5859C4.38279 28.6641 6.67967 27.7032 9.49218 27.7031C12.3047 27.7032 14.625 28.6641 16.4531 30.5859C18.2812 32.5079 19.1953 35.1798 19.1953 38.6016M9.70312 18.7734C7.03123 18.7735 4.73436 17.9532 2.8125 16.3125C0.93748 14.672 -9.99991e-06 12.3517 8.66294e-11 9.35156C-9.99991e-06 6.63291 0.96092 4.40634 2.88281 2.67187C4.85154 0.89072 7.12498 0.0001 9.70312 0C12.1875 0.0001 14.3906 0.79697 16.3125 2.39062C18.2343 3.98447 19.1953 6.30478 19.1953 9.35156C19.1953 12.3048 18.2578 14.6251 16.3828 16.3125C14.5078 17.9532 12.2812 18.7735 9.70312 18.7734"/> + </g> + <path id="path4171" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46647)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/locked.svg b/apps/shorty/img/usage/locked.svg new file mode 100644 index 00000000000..1691a9dfa4d --- /dev/null +++ b/apps/shorty/img/usage/locked.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062897958" y1="-2.28811738018" x2="1.88918016404" y2="-1.09199169808" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5393" transform="translate(-2.11465e-06, -2.863e-06)" fill="none"> + <path id="path4197" transform="matrix(0.758527 0 0 0.768105 2.64698e-22 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4199" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47751)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="g4220" transform="translate(46.2074, 35.1119)" fill="none"> + <path id="rect4189" transform="matrix(0.758527 0 0 0.758527 10.0979 0)" fill="#eeeeee" d="M11.875 0C5.28309 0 0 5.3085 0 11.9062L0 37.0938L12.7188 37.0938L12.7188 22.9688C12.7188 16.371 18.0331 11.0625 24.625 11.0625L50.125 11.0625C56.7169 11.0625 62.0312 16.371 62.0312 22.9688L62.0312 37.0938L74.2188 37.0938L74.2188 11.9062C74.2188 5.3085 68.9044 0 62.3125 0Z"/> + <path id="rect4193" transform="matrix(0.758527 0 0 0.758527 0 32.6878)" fill="#eeeeee" d="M11.9062 0C5.31434 0 0 5.3085 0 11.9062L0 26.875C0 33.4728 5.31434 38.7812 11.9062 38.7812L87.8125 38.7812C93.6895 38.7812 98.5472 34.5601 99.5312 28.9687L87.9375 28.9687C81.3456 28.9687 76.0312 25.575 76.0312 21.3438C76.0312 17.1125 81.3456 13.6875 87.9375 13.6875L99.7188 13.6875L99.7188 11.9062C99.7188 5.3085 94.4044 0 87.8125 0Z"/> + <path id="path4218" transform="matrix(0.758527 0 0 0.758527 0 67.4477)" fill="#eeeeee" d="M11.9062 0C5.31434 0 0 5.3085 0 11.9062L0 26.875C0 33.4728 5.31434 38.7812 11.9062 38.7812L87.8125 38.7812C93.6895 38.7812 98.5472 34.5601 99.5312 28.9687L87.9375 28.9687C81.3456 28.9687 76.0312 25.575 76.0312 21.3438C76.0312 17.1125 81.3456 13.6875 87.9375 13.6875L99.7188 13.6875L99.7188 11.9062C99.7188 5.3085 94.4044 0 87.8125 0Z"/> + </g> + <path id="path4201" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46647)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/network.svg b/apps/shorty/img/usage/network.svg new file mode 100644 index 00000000000..1d3a0257121 --- /dev/null +++ b/apps/shorty/img/usage/network.svg @@ -0,0 +1,34 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062886879" y1="-2.28811738018" x2="1.88918005155" y2="-1.09199169808" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5449" transform="translate(-8.40215e-06, -2.8318e-06)" fill="none"> + <path id="path5051" transform="matrix(0.758527 0 0 0.768105 1.05879e-21 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path5053" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47751)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="g5152" transform="translate(24.1282, 25.4609)" fill="none"> + <path id="path5092" transform="matrix(0.7132 0 0 0.7132 29.7461 0)" fill="#eeeeee" d="M9.9163 0C4.4218 0 0 4.14395 0 9.293L0 44.7222C0 49.8712 4.4218 54.0153 9.9163 54.0153L73.1505 54.0153C78.645 54.0153 83.0668 49.8712 83.0668 44.7222L83.0668 9.293C83.0668 4.14395 78.645 0 73.1505 0ZM19.0295 8.14427L64.0374 8.14427C69.5318 8.14427 73.9537 12.2882 73.9537 17.4373L73.9537 36.5778C73.9537 41.7269 69.5318 45.8709 64.0374 45.8709L19.0295 45.8709C13.535 45.8709 9.1132 41.7269 9.1132 36.5778L9.1132 17.4373C9.1132 12.2882 13.535 8.14427 19.0295 8.14427Z"/> + <rect id="rect5098" transform="matrix(0.7132 0 0 0.7132 0 75.1881)" fill="#eeeeee" width="38.99506800000pt" height="30.13255280000pt" rx="11.21705440000pt" ry="11.21705440000pt"/> + <rect id="rect5114" transform="matrix(0.7132 0 0 0.7132 86.1201 75.9782)" fill="#eeeeee" width="38.99506800000pt" height="30.13255280000pt" rx="11.21705440000pt" ry="11.21705440000pt"/> + <rect id="rect5116" transform="matrix(0.7132 0 0 0.7132 42.665 75.9782)" fill="#eeeeee" width="38.99506800000pt" height="30.13255280000pt" rx="11.21705440000pt" ry="11.21705440000pt"/> + <g id="g5138" transform="translate(8.18351, 44.967)" fill="none"> + <rect id="rect5126" transform="matrix(0.7132 0 0 0.7132 48.3081 8.88178e-15)" fill="#eeeeee" width="7.31157528000pt" height="29.91099280000pt"/> + <rect id="rect5128" transform="matrix(0.7132 0 0 0.7132 91.8912 8.69104)" fill="#eeeeee" width="7.53313824000pt" height="20.16222400000pt"/> + <rect id="rect5134" transform="matrix(0.7132 0 0 0.7132 0 8.69104)" fill="#eeeeee" width="7.53313824000pt" height="20.16222400000pt"/> + <rect id="rect5136" transform="matrix(0.7132 0 0 0.7132 -8.88178e-15 8.69104)" fill="#eeeeee" width="110.60805600000pt" height="8.61677440000pt"/> + </g> + <rect id="rect5144" transform="matrix(0.7132 0 0 0.7132 42.2636 10.4152)" fill="#eeeeee" width="39.63716160000pt" height="4.23005296000pt"/> + <rect id="rect5146" transform="matrix(0.7132 0 0 0.7132 42.2636 10.4152)" fill="#eeeeee" width="39.63716160000pt" height="4.23005296000pt"/> + <rect id="rect5148" transform="matrix(0.7132 0 0 0.7132 42.2636 17.5472)" fill="#eeeeee" width="39.63716160000pt" height="4.23005296000pt"/> + <rect id="rect5150" transform="matrix(0.7132 0 0 0.7132 42.2636 24.6792)" fill="#eeeeee" width="39.63716160000pt" height="4.23005296000pt"/> + </g> + <path id="path5055" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46647)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/qrcode.svg b/apps/shorty/img/usage/qrcode.svg new file mode 100644 index 00000000000..83802042f7a --- /dev/null +++ b/apps/shorty/img/usage/qrcode.svg @@ -0,0 +1,271 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062897958" y1="-2.28811738018" x2="1.88918016404" y2="-1.09199169808" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5381" transform="translate(-5.94477e-06, 2.56921e-06)" fill="none"> + <path id="path4167" transform="matrix(0.758527 0 0 0.768105 1.41962e-15 -6.05492e-16)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4169" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47751)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="text4182" transform="translate(5.94477e-06, -2.56921e-06)" fill="none"/> + <path id="path4171" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46647)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + <g id="group0" transform="translate(31.4638, 31.6895)" fill="none"> + <rect id="p" transform="translate(0, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p1" transform="translate(0, 7.66166)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p2" transform="translate(0, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p3" transform="translate(0, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p4" transform="translate(0, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p5" transform="translate(0, 27.1293)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p6" transform="translate(0, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p7" transform="translate(0, 41.7301)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p8" transform="translate(0, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p9" transform="translate(0, 61.1977)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p10" transform="translate(0, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p11" transform="translate(0, 75.7985)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p12" transform="translate(0, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p13" transform="translate(0, 85.5323)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p14" transform="translate(0, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p15" transform="translate(0, 95.2662)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p16" transform="translate(0, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p17" transform="translate(4.95608, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p18" transform="translate(4.95608, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p19" transform="translate(4.95608, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p20" transform="translate(4.95608, 61.1977)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p21" transform="translate(4.95608, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p22" transform="translate(4.95608, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p23" transform="translate(9.91217, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p24" transform="translate(9.91217, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p25" transform="translate(9.91217, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p26" transform="translate(9.91217, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p27" transform="translate(9.91217, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p28" transform="translate(9.91217, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p29" transform="translate(9.91217, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p30" transform="translate(9.91217, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p31" transform="translate(9.91217, 61.1977)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p32" transform="translate(9.91217, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p33" transform="translate(9.91217, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p34" transform="translate(9.91217, 85.5323)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p35" transform="translate(9.91217, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p36" transform="translate(9.91217, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p37" transform="translate(14.8683, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p38" transform="translate(14.8683, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p39" transform="translate(14.8683, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p40" transform="translate(14.8683, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p41" transform="translate(14.8683, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p42" transform="translate(14.8683, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p43" transform="translate(14.8683, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p44" transform="translate(14.8683, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p45" transform="translate(14.8683, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p46" transform="translate(14.8683, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p47" transform="translate(14.8683, 85.5323)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p48" transform="translate(14.8683, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p49" transform="translate(14.8683, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p50" transform="translate(19.8243, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p51" transform="translate(19.8243, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p52" transform="translate(19.8243, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p53" transform="translate(19.8243, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p54" transform="translate(19.8243, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p55" transform="translate(19.8243, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p56" transform="translate(19.8243, 61.1977)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p57" transform="translate(19.8243, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p58" transform="translate(19.8243, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p59" transform="translate(19.8243, 85.5323)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p60" transform="translate(19.8243, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p61" transform="translate(19.8243, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p62" transform="translate(24.7804, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p63" transform="translate(24.7804, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p64" transform="translate(24.7804, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p65" transform="translate(24.7804, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p66" transform="translate(24.7804, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p67" transform="translate(24.7804, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p68" transform="translate(24.7804, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p69" transform="translate(29.7365, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p70" transform="translate(29.7365, 7.66166)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p71" transform="translate(29.7365, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p72" transform="translate(29.7365, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p73" transform="translate(29.7365, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p74" transform="translate(29.7365, 27.1293)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p75" transform="translate(29.7365, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p76" transform="translate(29.7365, 41.7301)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p77" transform="translate(29.7365, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p78" transform="translate(29.7365, 61.1977)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p79" transform="translate(29.7365, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p80" transform="translate(29.7365, 75.7985)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p81" transform="translate(29.7365, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p82" transform="translate(29.7365, 85.5323)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p83" transform="translate(29.7365, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p84" transform="translate(29.7365, 95.2662)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p85" transform="translate(29.7365, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p86" transform="translate(34.6926, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p87" transform="translate(34.6926, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p88" transform="translate(34.6926, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p89" transform="translate(39.6487, 7.66166)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p90" transform="translate(39.6487, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p91" transform="translate(39.6487, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p92" transform="translate(39.6487, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p93" transform="translate(39.6487, 36.8632)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p94" transform="translate(39.6487, 41.7301)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p95" transform="translate(39.6487, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p96" transform="translate(39.6487, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p97" transform="translate(39.6487, 61.1977)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p98" transform="translate(39.6487, 66.0647)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p99" transform="translate(39.6487, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p100" transform="translate(44.6048, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p101" transform="translate(44.6048, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p102" transform="translate(44.6048, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p103" transform="translate(44.6048, 27.1293)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p104" transform="translate(44.6048, 36.8632)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p105" transform="translate(44.6048, 41.7301)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p106" transform="translate(44.6048, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p107" transform="translate(44.6048, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p108" transform="translate(44.6048, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p109" transform="translate(44.6048, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p110" transform="translate(44.6048, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p111" transform="translate(44.6048, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p112" transform="translate(49.5608, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p113" transform="translate(49.5608, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p114" transform="translate(49.5608, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p115" transform="translate(49.5608, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p116" transform="translate(49.5608, 61.1977)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p117" transform="translate(49.5608, 66.0647)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p118" transform="translate(49.5608, 75.7985)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p119" transform="translate(49.5608, 85.5323)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p120" transform="translate(49.5608, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p121" transform="translate(54.5169, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p122" transform="translate(54.5169, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p123" transform="translate(54.5169, 36.8632)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p124" transform="translate(54.5169, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p125" transform="translate(54.5169, 66.0647)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p126" transform="translate(54.5169, 75.7985)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p127" transform="translate(54.5169, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p128" transform="translate(59.473, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p129" transform="translate(59.473, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p130" transform="translate(59.473, 27.1293)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p131" transform="translate(59.473, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p132" transform="translate(59.473, 36.8632)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p133" transform="translate(59.473, 41.7301)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p134" transform="translate(59.473, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p135" transform="translate(59.473, 66.0647)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p136" transform="translate(59.473, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p137" transform="translate(59.473, 75.7985)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p138" transform="translate(59.473, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p139" transform="translate(59.473, 85.5323)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p140" transform="translate(64.4291, 41.7301)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p141" transform="translate(64.4291, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p142" transform="translate(64.4291, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p143" transform="translate(64.4291, 61.1977)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p144" transform="translate(64.4291, 66.0647)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p145" transform="translate(64.4291, 75.7985)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p146" transform="translate(64.4291, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p147" transform="translate(69.3852, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p148" transform="translate(69.3852, 7.66166)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p149" transform="translate(69.3852, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p150" transform="translate(69.3852, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p151" transform="translate(69.3852, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p152" transform="translate(69.3852, 27.1293)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p153" transform="translate(69.3852, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p154" transform="translate(69.3852, 41.7301)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p155" transform="translate(69.3852, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p156" transform="translate(69.3852, 61.1977)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p157" transform="translate(69.3852, 66.0647)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p158" transform="translate(69.3852, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p159" transform="translate(69.3852, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p160" transform="translate(74.3413, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p161" transform="translate(74.3413, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p162" transform="translate(74.3413, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p163" transform="translate(74.3413, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p164" transform="translate(74.3413, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p165" transform="translate(74.3413, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p166" transform="translate(74.3413, 85.5323)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p167" transform="translate(74.3413, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p168" transform="translate(74.3413, 95.2662)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p169" transform="translate(74.3413, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p170" transform="translate(79.2974, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p171" transform="translate(79.2974, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p172" transform="translate(79.2974, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p173" transform="translate(79.2974, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p174" transform="translate(79.2974, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p175" transform="translate(79.2974, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p176" transform="translate(79.2974, 66.0647)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p177" transform="translate(79.2974, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p178" transform="translate(79.2974, 85.5323)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p179" transform="translate(79.2974, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p180" transform="translate(79.2974, 95.2662)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p181" transform="translate(84.2534, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p182" transform="translate(84.2534, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p183" transform="translate(84.2534, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p184" transform="translate(84.2534, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p185" transform="translate(84.2534, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p186" transform="translate(84.2534, 41.7301)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p187" transform="translate(84.2534, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p188" transform="translate(84.2534, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p189" transform="translate(84.2534, 66.0647)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p190" transform="translate(84.2534, 75.7985)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p191" transform="translate(84.2534, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p192" transform="translate(84.2534, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p193" transform="translate(84.2534, 95.2662)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p194" transform="translate(84.2534, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p195" transform="translate(89.2095, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p196" transform="translate(89.2095, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p197" transform="translate(89.2095, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p198" transform="translate(89.2095, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p199" transform="translate(89.2095, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p200" transform="translate(89.2095, 41.7301)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p201" transform="translate(89.2095, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p202" transform="translate(89.2095, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p203" transform="translate(89.2095, 56.3308)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p204" transform="translate(89.2095, 66.0647)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p205" transform="translate(89.2095, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p206" transform="translate(89.2095, 75.7985)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p207" transform="translate(89.2095, 85.5323)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p208" transform="translate(89.2095, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p209" transform="translate(89.2095, 95.2662)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p210" transform="translate(94.1656, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p211" transform="translate(94.1656, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p212" transform="translate(94.1656, 41.7301)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p213" transform="translate(94.1656, 46.597)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p214" transform="translate(94.1656, 51.4639)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p215" transform="translate(94.1656, 61.1977)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p216" transform="translate(94.1656, 70.9316)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p217" transform="translate(94.1656, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p218" transform="translate(94.1656, 100.133)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p219" transform="translate(99.1217, 2.79474)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p220" transform="translate(99.1217, 7.66166)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p221" transform="translate(99.1217, 12.5286)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p222" transform="translate(99.1217, 17.3955)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p223" transform="translate(99.1217, 22.2624)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p224" transform="translate(99.1217, 27.1293)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p225" transform="translate(99.1217, 31.9962)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p226" transform="translate(99.1217, 66.0647)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p227" transform="translate(99.1217, 75.7985)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p228" transform="translate(99.1217, 80.6654)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + <rect id="p229" transform="translate(99.1217, 90.3992)" fill="#ffffff" stroke="#000000" stroke-width="0.00000000000" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="3.96486751181pt" height="3.89353363095pt"/> + </g> + <rect id="shape0" transform="translate(73.7513, 37.3739)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape1" transform="translate(84.0513, 39.0469)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape2" transform="translate(82.9589, 61.8606)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape3" transform="translate(73.7513, 37.3739)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape4" transform="translate(72.6589, 52.2789)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape5" transform="translate(83.8952, 72.507)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape6" transform="translate(48.4696, 74.18)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape7" transform="translate(34.2682, 77.8302)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape8" transform="translate(73.9074, 95.1686)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape9" transform="translate(73.4392, 120.112)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape10" transform="translate(72.0347, 107.792)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape11" transform="translate(118.384, 85.7389)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape12" transform="translate(125.719, 114.18)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape13" transform="translate(90.6058, 123.762)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape14" transform="translate(87.7967, 92.8872)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape15" transform="translate(104.651, 105.207)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape16" transform="translate(93.8831, 115.853)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape17" transform="translate(106.836, 76.3093)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape18" transform="translate(108.553, 125.739)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + <rect id="shape19" transform="translate(125.251, 75.5488)" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" width="7.74057149730pt" height="8.39543189174pt"/> + </g> +</svg> diff --git a/apps/shorty/img/usage/sms.svg b/apps/shorty/img/usage/sms.svg new file mode 100644 index 00000000000..5d519df9570 --- /dev/null +++ b/apps/shorty/img/usage/sms.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062891915" y1="-2.28811733465" x2="1.88918010268" y2="-1.09199167635" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5434" transform="translate(-6.50233e-06, 2.52429e-06)" fill="none"> + <path id="path5075" transform="matrix(0.758527 0 0 0.768105 1.05879e-21 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path5077" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47756)" fill="#000000" stroke="#000000" stroke-width="1.25000000000" stroke-linecap="square" stroke-linejoin="miter" stroke-miterlimit="2.00000000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="rect5206" transform="matrix(0.758527 0 0 0.758527 28.5135 43.1225)" fill="#eeeeee" d="M12 0C5.352 0 0 5.352 0 12L0 72.5937C0 79.2417 5.352 84.5937 12 84.5937L83.4687 84.5937C92.9385 97.8632 117.244 131.838 117.469 130.938C117.697 130.027 118.047 97.894 118.188 84.5937L129 84.5937C135.648 84.5937 141 79.2417 141 72.5937L141 12C141 5.352 135.648 1.13687e-13 129 1.13687e-13ZM29.8125 25.2812C31.4969 25.2813 33.0089 25.5233 34.3437 26C35.6946 26.4768 36.7976 27.1045 37.6875 27.9063C38.5932 28.7081 39.2892 29.6186 39.75 30.5937C40.2268 31.5689 40.4687 32.5057 40.4687 33.4375C40.4687 34.456 40.1959 35.2874 39.6875 35.9375C39.1948 36.5876 38.4842 36.9063 37.5625 36.9062C36.8951 36.9063 36.3205 36.6451 35.8437 36.125C35.383 35.6049 34.8537 34.8527 34.25 33.8125C33.7573 32.9457 33.1984 32.2388 32.5313 31.7187C31.8637 31.1987 30.9566 30.9375 29.8125 30.9375C28.6366 30.9375 27.6536 31.2753 26.875 31.9687C26.0963 32.6405 25.7187 33.4815 25.7187 34.5C25.7187 35.4318 25.9904 36.2057 26.5625 36.8125C27.1345 37.3976 27.9056 37.8912 28.875 38.2812C29.8444 38.6713 31.1747 39.1553 32.875 39.7187C34.8932 40.3905 36.5412 41.1932 37.8125 42.125C39.0997 43.0568 40.0673 44.1589 40.7187 45.4375C41.3863 46.6944 41.7187 48.1247 41.7187 49.75C41.7187 52.1988 41.2802 54.3072 40.4063 56.0625C39.5322 57.7961 38.2474 59.1211 36.5313 60.0312C34.8308 60.9197 32.7597 61.375 30.3125 61.375C27.9765 61.375 25.9811 60.8814 24.3125 59.9062C22.6439 58.9311 21.3884 57.7019 20.5937 56.25C19.7993 54.7764 19.4063 53.3173 19.4063 51.8437C19.4063 50.8686 19.679 50.0372 20.1875 49.3437C20.696 48.6503 21.3151 48.2813 22.0937 48.2812C22.7773 48.2813 23.322 48.5137 23.6875 48.9687C24.053 49.4238 24.3852 50.0828 24.7187 50.9062C25.3863 52.4882 26.2033 53.6573 27.125 54.4375C28.0625 55.2176 29.3325 55.625 30.9375 55.625C32.2405 55.625 33.2987 55.2176 34.125 54.4375C34.9672 53.6357 35.375 52.7373 35.375 51.7187C35.375 50.1585 34.9364 48.9964 34.0625 48.2812C33.2044 47.5661 31.7988 46.9001 29.8125 46.25C27.5719 45.4915 25.7268 44.6985 24.3125 43.875C22.9141 43.0299 21.811 41.9277 20.9687 40.5625C20.1267 39.1973 19.6875 37.5249 19.6875 35.5312C19.6875 33.7543 20.0964 32.0507 20.875 30.4687C21.6536 28.8868 22.8028 27.6506 24.3125 26.7188C25.838 25.7653 27.6673 25.2813 29.8125 25.2812ZM49.9687 25.2812C50.8587 25.2813 51.5995 25.7078 52.1875 26.5312C52.7912 27.3331 53.0937 28.4448 53.0937 29.875L53.0937 30.7187C54.2221 28.8768 55.4316 27.5231 56.7187 26.6563C58.006 25.7895 59.4268 25.3438 61 25.3438C62.6368 25.3438 64.0429 25.799 65.2187 26.6875C66.3947 27.576 67.3621 28.9201 68.125 30.7187C69.2214 28.8985 70.4007 27.5544 71.6563 26.6875C72.9115 25.799 74.3182 25.3438 75.8437 25.3438C77.6236 25.3438 79.1503 25.8278 80.4375 26.7812C81.7247 27.7348 82.6768 29.098 83.3125 30.875C83.8686 32.4786 84.1561 34.9919 84.1563 38.4375L84.1563 55.7812C84.156 57.6449 83.8385 59.0369 83.2187 59.9687C82.5991 60.9006 81.7982 61.375 80.7813 61.375C79.7959 61.375 78.9794 60.9006 78.3437 59.9687C77.7241 59.0152 77.4063 57.6232 77.4063 55.7812L77.4063 40.8437C77.4063 38.9368 77.3463 37.4298 77.2187 36.2812C77.1078 35.1327 76.7744 34.1551 76.25 33.375C75.7256 32.5949 74.9397 32.2188 73.875 32.2187C73.0169 32.2188 72.2161 32.5566 71.4375 33.25C70.6747 33.9435 70.0541 34.8611 69.625 36.0312C69.1483 37.5265 68.9063 40.1764 68.9063 43.9687L68.9063 55.7812C68.9063 57.6449 68.6197 59.0369 68 59.9687C67.3802 60.9006 66.5482 61.375 65.5313 61.375C64.5459 61.375 63.7447 60.9006 63.125 59.9687C62.5211 59.0369 62.2187 57.6449 62.2187 55.7812L62.2187 41.625C62.2187 39.3929 62.1737 37.6727 62.0625 36.4375C61.9514 35.2023 61.6487 34.1864 61.1563 33.4062C60.6636 32.6045 59.8772 32.2188 58.8125 32.2187C56.6831 32.2188 55.2772 33.1938 54.5937 35.1875C53.9264 37.1812 53.5937 40.0539 53.5937 43.7812L53.5937 55.7812C53.5937 57.6232 53.2759 59.0152 52.6563 59.9687C52.0523 60.9006 51.2511 61.375 50.25 61.375C49.2648 61.375 48.4482 60.9006 47.8125 59.9687C47.1928 59.0152 46.9061 57.6232 46.9063 55.7812L46.9063 30.375C46.9063 28.7064 47.1627 27.4606 47.7187 26.5937C48.291 25.727 49.0471 25.2813 49.9687 25.2812ZM99.5 25.2812C101.184 25.2813 102.697 25.5233 104.031 26C105.382 26.4768 106.516 27.1045 107.406 27.9063C108.312 28.7081 108.977 29.6186 109.438 30.5937C109.914 31.5689 110.156 32.5057 110.156 33.4375C110.156 34.456 109.915 35.2874 109.406 35.9375C108.914 36.5876 108.203 36.9063 107.281 36.9062C106.614 36.9063 106.039 36.6451 105.562 36.125C105.102 35.6049 104.573 34.8527 103.969 33.8125C103.476 32.9457 102.886 32.2388 102.219 31.7187C101.551 31.1987 100.644 30.9375 99.5 30.9375C98.324 30.9375 97.3412 31.2753 96.5625 31.9687C95.7839 32.6405 95.4062 33.4815 95.4063 34.5C95.4063 35.4318 95.678 36.2057 96.25 36.8125C96.8221 37.3976 97.5931 37.8912 98.5625 38.2812C99.5318 38.6713 100.862 39.1553 102.562 39.7187C104.581 40.3905 106.229 41.1932 107.5 42.125C108.787 43.0568 109.755 44.1589 110.406 45.4375C111.074 46.6944 111.406 48.1247 111.406 49.75C111.406 52.1988 110.968 54.3072 110.094 56.0625C109.22 57.7961 107.935 59.1211 106.219 60.0312C104.519 60.9197 102.447 61.375 100 61.375C97.6641 61.375 95.6686 60.8814 94 59.9062C92.3314 58.9311 91.1071 57.7019 90.3125 56.25C89.518 54.7764 89.0938 53.3173 89.0937 51.8437C89.0937 50.8686 89.3665 50.0372 89.875 49.3437C90.3834 48.6503 91.0339 48.2813 91.8125 48.2812C92.4958 48.2813 93.0095 48.5137 93.375 48.9687C93.7404 49.4238 94.1038 50.0828 94.4375 50.9062C95.1049 52.4882 95.8907 53.6573 96.8125 54.4375C97.75 55.2176 99.0199 55.625 100.625 55.625C101.928 55.625 102.986 55.2176 103.813 54.4375C104.655 53.6357 105.094 52.7373 105.094 51.7187C105.094 50.1585 104.655 48.9964 103.781 48.2812C102.923 47.5661 101.486 46.9001 99.5 46.25C97.2593 45.4915 95.4456 44.6985 94.0313 43.875C92.6329 43.0299 91.4985 41.9277 90.6563 40.5625C89.814 39.1973 89.4063 37.5249 89.4063 35.5312C89.4063 33.7543 89.7839 32.0507 90.5625 30.4687C91.3411 28.8868 92.4903 27.6506 94 26.7188C95.5255 25.7653 97.3548 25.2813 99.5 25.2812Z"/> + <path id="path5079" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46648)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/team.svg b/apps/shorty/img/usage/team.svg new file mode 100644 index 00000000000..c2d3c0075d2 --- /dev/null +++ b/apps/shorty/img/usage/team.svg @@ -0,0 +1,20 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062898865" y1="-2.28811738018" x2="1.88918017325" y2="-1.09199169808" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5258" transform="translate(-2.67397e-06, 5.0533e-06)" fill="none"> + <path id="path4049" transform="matrix(0.758527 0 0 0.768105 5.29396e-22 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4051" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47748)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4066" transform="matrix(0.758527 0 0 0.758527 28.6825 27.5818)" fill="#eeeeee" d="M51.3117 0C34.1148 0 20.1891 15.2419 20.1891 34.0447C20.1891 44.7741 24.7371 54.3331 31.8306 60.5733C16.506 70.8805 4.63895 92.9893 0 120.395L55.1922 120.395C59.0298 99.7894 68.1076 83.2199 79.7599 75.3826C75.6622 71.7778 72.6402 66.7497 71.3435 60.9909C71.1645 60.8664 70.999 60.7224 70.8191 60.6012C70.9527 60.4838 71.0806 60.359 71.2124 60.2393C70.8546 58.4247 70.6355 56.5482 70.6355 54.6162C70.6355 44.9453 75.3345 36.4865 82.3819 31.8177C81.3314 14.0536 67.8239 0 51.3117 0Z"/> + <path id="path4076" transform="matrix(0.758527 0 0 0.758527 79.2535 53.036)" fill="#eeeeee" d="M40.1579 0C26.6991 0 15.8005 11.9287 15.8005 26.6442C15.8005 35.0414 19.3599 42.5225 24.9114 47.4063C12.918 55.4729 3.63055 72.7758 0 94.2243L80.3158 94.2243C76.6873 72.791 67.4064 55.5019 55.4248 47.428C60.9821 42.5445 64.5358 35.0463 64.5358 26.6442C64.5358 11.9287 53.6166 0 40.1579 0Z"/> + <path id="path4053" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46644)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.896 205.25 106.73 205.25 106.562C205.25 47.725 159.299 0 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/unlocked.svg b/apps/shorty/img/usage/unlocked.svg new file mode 100644 index 00000000000..b993bd1458b --- /dev/null +++ b/apps/shorty/img/usage/unlocked.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062897958" y1="-2.28811733465" x2="1.88918016404" y2="-1.09199167635" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5416" transform="translate(-2.95322e-06, -2.15252e-07)" fill="none"> + <path id="path4251" transform="matrix(0.758527 0 0 0.768105 5.29396e-22 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4253" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47756)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="g5406" transform="translate(23.3294, 40.9941)" fill="none"> + <path id="path4263" transform="matrix(0.758527 0 0 0.758527 0 0)" fill="#eeeeee" d="M11.875 0C5.28309 0 0 5.3085 0 11.9062L0 37.0938L12.7188 37.0938L12.7188 22.9688C12.7188 16.371 18.0331 11.0625 24.625 11.0625L50.125 11.0625C56.7169 11.0625 62.0312 16.371 62.0312 22.9688L62.0312 37.0938L74.2188 37.0938L74.2188 11.9062C74.2188 5.3085 68.9044 0 62.3125 0Z"/> + <path id="path4265" transform="matrix(0.758527 0 0 0.758527 37.7996 31.8475)" fill="#eeeeee" d="M11.9062 1.13687e-13C5.31434 1.13687e-13 0 5.3085 0 11.9062L0 26.875C0 33.4727 5.31434 38.7812 11.9062 38.7812L87.8125 38.7812C93.6895 38.7812 98.5472 34.5601 99.5312 28.9687L87.9375 28.9687C81.3456 28.9687 76.0312 25.575 76.0312 21.3437C76.0312 17.1125 81.3456 13.6875 87.9375 13.6875L99.7188 13.6875L99.7188 11.9062C99.7188 5.3085 94.4044 0 87.8125 0Z"/> + <path id="path4267" transform="matrix(0.758527 0 0 0.758527 37.7996 66.6074)" fill="#eeeeee" d="M11.9062 0C5.31434 0 0 5.3085 0 11.9063L0 26.875C0 33.4728 5.31434 38.7813 11.9062 38.7813L87.8125 38.7813C93.6895 38.7813 98.5472 34.5601 99.5312 28.9688L87.9375 28.9688C81.3456 28.9688 76.0312 25.575 76.0312 21.3438C76.0312 17.1126 81.3456 13.6875 87.9375 13.6875L99.7188 13.6875L99.7188 11.9063C99.7188 5.3085 94.4044 0 87.8125 0Z"/> + </g> + <path id="path4255" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46648)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.562C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.062C205.251 106.895 205.25 106.73 205.25 106.562C205.25 47.725 159.299 -1.13687e-13 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/img/usage/workstation.svg b/apps/shorty/img/usage/workstation.svg new file mode 100644 index 00000000000..104d98f8552 --- /dev/null +++ b/apps/shorty/img/usage/workstation.svg @@ -0,0 +1,22 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon, part of Calligra: http://www.calligra.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="133.098pt" height="134.778pt"> +<defs> + <linearGradient id="gradient0" gradientTransform="matrix(0.935714 0 0 0.971429 -260.198 309.044)" gradientUnits="objectBoundingBox" x1="1.86062897958" y1="-2.28811733465" x2="1.88918016404" y2="-1.09199167635" spreadMethod="pad"> + <stop stop-color="#edf4fd" offset="0.00000000000" stop-opacity="0.52845044633"/> + <stop stop-color="#175bb3" offset="1.00000000000" stop-opacity="0.00000000000"/> + </linearGradient> + </defs> +<g id="layer1"> + <g id="g5228" transform="translate(7.95475e-07, 1.12198e-05)" fill="none"> + <path id="path4227" transform="matrix(0.758527 0 0 0.768105 0 0)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <path id="path4229" transform="matrix(0.709764 0 0 0.736855 5.34768 4.47748)" fill="#000000" d="M219.336 109.668C219.336 170.236 170.236 219.336 109.668 219.336C49.1001 219.336 0 170.236 0 109.668C0 49.1001 49.1001 0 109.668 0C170.236 0 219.336 49.1001 219.336 109.668Z"/> + <g id="g5179" transform="translate(32.168, 32.4772)" fill="none"> + <path id="rect5085" transform="matrix(0.758527 0 0 0.758527 5.76033 -8.88178e-15)" fill="#eeeeee" d="M14.0643 1.13687e-13C6.27157 1.13687e-13 0 6.74806 0 15.1328L0 72.8262C0 81.211 6.27157 87.959 14.0643 87.959L103.749 87.959C111.542 87.959 117.814 81.211 117.814 72.8262L117.814 15.1328C117.814 6.74806 111.542 0 103.749 0ZM26.9895 13.2622L90.8242 13.2622C98.6169 13.2622 104.889 20.0103 104.889 28.3951L104.889 59.5638C104.889 67.9486 98.6169 74.6968 90.8242 74.6968L26.9895 74.6968C19.1968 74.6968 12.9252 67.9486 12.9252 59.5638L12.9252 28.3951C12.9252 20.0103 19.1968 13.2622 26.9895 13.2622Z"/> + <path id="rect5167" transform="matrix(0.758527 0 0 0.758527 -4.44089e-15 73.5695)" fill="#eeeeee" d="M5 0C2.23 0 0 2.23 0 5L0 31.125C0 33.895 2.23 36.125 5 36.125L127.938 36.125C130.708 36.125 132.938 33.895 132.938 31.125L132.938 5C132.938 2.23 130.708 0 127.938 0ZM15.375 9C19.5823 9 22.9688 12.0823 22.9688 15.9062C22.9688 19.7302 19.5823 22.8438 15.375 22.8438C11.1677 22.8438 7.75 19.7302 7.75 15.9062C7.75 12.0823 11.1677 9 15.375 9ZM78.0938 9.53125L118.5 9.53125C121.27 9.53125 123.5 11.7613 123.5 14.5312L123.5 16.1875C123.5 18.9575 121.27 21.1875 118.5 21.1875L78.0938 21.1875C75.3237 21.1875 73.0938 18.9575 73.0938 16.1875L73.0938 14.5312C73.0938 11.7613 75.3237 9.53125 78.0938 9.53125Z"/> + </g> + <path id="path4231" transform="matrix(0.758527 0 0 0.758527 5.33866 4.46648)" fill="url(#gradient0)" d="M102.625 0C45.9507 0 0 47.725 0 106.563C0 110.315 0.1979 114.004 0.5625 117.656C50.6291 136.382 127.144 150.025 205.25 107.063C205.251 106.896 205.25 106.73 205.25 106.563C205.25 47.725 159.299 1.13687e-13 102.625 0Z"/> + </g> + </g> +</svg> diff --git a/apps/shorty/index.php b/apps/shorty/index.php new file mode 100644 index 00000000000..8c729bae149 --- /dev/null +++ b/apps/shorty/index.php @@ -0,0 +1,149 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file index.php + * This is the plugins central position + * All requests to the plugin are handled by this file. + * Exceptions: system settings, user preferences and relaying + * @access public + * @author Christian Reiner + */ + +OCP\App::setActiveNavigationEntry ( 'shorty_index' ); + +OCP\Util::addStyle ( 'shorty', 'shorty' ); + +OCP\Util::addScript ( 'shorty/3rdparty','jquery.tinysort.min' ); +OCP\Util::addScript ( 'shorty', 'shorty' ); +OCP\Util::addScript ( 'shorty', 'init' ); +if ( OC_Log::DEBUG==OC_Config::getValue( "loglevel", OC_Log::WARN ) ) + OCP\Util::addScript ( 'shorty', 'debug' ); + +// strategy: +// - first: decide which action is requested +// - second: execute that action with an optional argument provided + +// defaults: +$act = 'index'; +$arg = NULL; +// we try to guess what the request indicates: +// - a (shorty) id to be looked up in the database resulting in a forwarding to the stored target +// - a (target) url to be added as a new shorty +// - none of the two, so just a plain list of existing shortys +foreach ($_GET as $key=>$val) // in case there are unexpected, additional arguments like a timestamp added by some stupid proxy +{ + switch ($key) + { + // this is the OC4 argument used to identify the app called, we ignore it: + case 'app': + break; + // any recognizable argument key indicating a url to be added as new shorty ? + case 'url': + case 'uri': + case 'target': + case 'link': + // example: http://.../shorty/index.php?url=http%... + $act = 'acquire'; + $arg = OC_Shorty_Type::req_argument($key,OC_Shorty_Type::URL,FALSE); + break 2; // skip switch AND foreach + // no recognizable key but something else, hm... + // this _might_ be some unexcepted argument, or: + // it is an expected argument, but without recognizable key, so we try to guess by examining the content + // we restrict this 'guessing' to cases where only a single argument is specified + default: + if ( (1==sizeof($_GET)) // only one single request argument + &&( ! reset($_GET)) ) // no value, so maybe just an id + { + // use that source instead of $key, since $key contains replaced chars (php specific exceptions due to var name problems) + $raw = urldecode($_SERVER['QUERY_STRING']); + // now try to interpret its content + if (NULL!==($value=OC_Shorty_Type::normalize($raw,OC_Shorty_Type::URL,FALSE))) + { + // the query string is a url, acquire it as a new shorty + $act = 'acquire'; + $arg = $raw; + break 2; + } + else + { + // no pattern recognized, so we assume an ordinary index action + $act = 'index'; + break 2; + } + } // if + $act='index'; + break 2; + } // switch key +} // foreach key + +// next, execute the "act" whilst considering the 'arg' +switch ($act) +{ + case 'acquire': // add url as new shorty + // keep the url specified as referer, that is the one we want to store + $_SESSION['shorty-referrer'] = $arg; + OCP\Util::writeLog( 'shorty', sprintf("Detected an incoming Shortlet request for url '%s...'",substr($arg,0,80)), OC_Log::INFO ); + header ( sprintf('Location: %s', OCP\Util::linkTo('shorty','index.php')) ); + exit(); + // ===== + case 'index': // action 'index': list of shortys + default: + try + { + // is this a redirect from a call with a target url to be added ? + if ( isset($_SESSION['shorty-referrer']) ) + { + // this takes care of handling the url on the client side + OCP\Util::addScript ( 'shorty', 'add' ); + // add url taked from the session vars to anything contained in the query string + $_SERVER['QUERY_STRING'] = implode('&',array_merge(array('url'=>$_SESSION['shorty-referrer']),explode('&',$_SERVER['QUERY_STRING']))); + } + else + { + // simple desktop initialization, no special actions contained + OCP\Util::addScript ( 'shorty', 'list' ); + } + $tmpl = new OCP\Template( 'shorty', 'tmpl_index', 'user' ); + // the (remote) base url of the qrcode generator + $tmpl->assign ( 'qrcode-url', sprintf('%s?service=%s&url=',OCP\Util::linkToAbsolute("", "public.php"),'shorty_qrcode') ); + // available status (required for select filter in toolbox) + $shorty_status['']=sprintf('- %s -',OC_Shorty_L10n::t('all')); + foreach ( OC_Shorty_Type::$STATUS as $status ) + $shorty_status[$status] = OC_Shorty_L10n::t($status); + $tmpl->assign ( 'shorty-status', $shorty_status ); + // any referrer we want to hand over to the browser ? + if ( array_key_exists('shorty-referrer',$_SESSION) ) + $tmpl->assign ( 'shorty-referrer', $_SESSION['shorty-referrer'] ); + // is sending sms enabled in the personal preferences ? + $tmpl->assign ( 'sms-control', OCP\Config::getUserValue(OCP\User::getUser(),'shorty','sms-control','disabled') ); + // clean up session var so that a browser reload does not trigger the same action again + unset ( $_SESSION['shorty-referrer'] ); + $tmpl->printPage(); + } catch ( OC_Shorty_Exception $e ) { OCP\JSON::error ( array ( 'message'=>$e->getTranslation(), 'data'=>$result ) ); } +} // switch + +?> diff --git a/apps/shorty/js/add.js b/apps/shorty/js/add.js new file mode 100644 index 00000000000..7b120d888ce --- /dev/null +++ b/apps/shorty/js/add.js @@ -0,0 +1,51 @@ +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file js/add.js + * @brief Client side desktop initialization in case of a call with an url to add + * @author Christian Reiner + */ + +$(document).ready(function(){ + // initialize desktop + var dialog = $('#dialog-add'); + $.when( + Shorty.WUI.Controls.init() + ).pipe(function(){ + Shorty.WUI.List.build(); + }).done(function(){ + $.when( + Shorty.WUI.Dialog.toggle(dialog) + ).done(function(){ + // any referrer handed over from php (explicitly in markup) ? + var target=$('#controls').attr('data-referrer'); + $('#controls').removeAttr('data-referrer'); + dialog.find('#target').val(target); + dialog.find('#title').focus(); + Shorty.WUI.Meta.collect(dialog); + }) + }) +}); // document.ready diff --git a/apps/shorty/js/debug.js b/apps/shorty/js/debug.js new file mode 100644 index 00000000000..a45819152ee --- /dev/null +++ b/apps/shorty/js/debug.js @@ -0,0 +1,71 @@ +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied wpayloadanty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file js/debug.js + * @brief Client side debugging methods + * The inclusion of these definitions trigger additional debug outputs + * @author Christian Reiner + */ + +$(document).ready(function(){ + $.extend(Shorty,{ + Debug:{ + log: function(issue){ + switch (typeof(issue)){ + case 'string': + console.log(issue); + break; + default: + console.log(this.dump(issue)); + } // switch + }, // Shorty.Debuglog() + + dump: function(payload,level){ + var dumped_text = ""; + if(!level) level = 0; + // some padding given at the beginning of the line + var level_padding = ""; + for(var j=0;j<level+1;j++) level_padding += " "; + + if(typeof(payload) == 'object') { + for(var item in payload) { + var value = payload[item]; + + if(typeof(value) == 'object') { + dumped_text += level_padding + "'" + item + "' ...\n"; + dumped_text += dump(value,level+1); + } else { + dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n"; + } + } + } else { //Stings/Chars/Numbers etc. + dumped_text = "==>"+payload+"<==("+typeof(payload)+")"; + } + return dumped_text; + } // Shorty.Debug.dump() + } // Shorty.Debug + }); +}); diff --git a/apps/shorty/js/init.js b/apps/shorty/js/init.js new file mode 100644 index 00000000000..3ab9fa7091a --- /dev/null +++ b/apps/shorty/js/init.js @@ -0,0 +1,92 @@ +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file js/init.js + * @brief Client side initialization of desktop actionss + * @author Christian Reiner + */ + +$(document).ready(function(){ + // make notification closeable + $('#content #notification').bind('click',Shorty.WUI.Notification.hide); + // button to open the 'add' dialog + $('#controls #add').bind('click',function(){Shorty.WUI.Dialog.toggle($('#dialog-add'))}); + // close button in dialogs + $('.shorty-dialog #close').bind('click',function(){Shorty.WUI.Dialog.hide($(this).parents('form').eq(0));}); + // status selection in embedded share dialog + $('.shorty-embedded#dialog-share #status').bind('change',function(){ + Shorty.Action.Url.status($(this).siblings('#id').val(),$(this).val()); + }); + // button to open the tools header row in the list + $('#list #titlebar').bind('click',Shorty.WUI.List.Toolbar.toggle); + // button to reload the list + $('#list #toolbar').find('#reload').bind('click',Shorty.WUI.List.build); + // sort buttons + $('#list #toolbar').find('shorty-sorter').bind('click',Shorty.WUI.List.sort); + // add date picker options + $.datepicker.setDefaults({ + dateFormat :'yy-mm-dd', + appendText: "(yyyy-mm-dd)", + changeMonth: true, + changeYear: true, + showOtherMonths: true, + selectOtherMonths: true, + showOn: 'button', + buttonImage: $('#controls').find('#until').eq(0).attr('icon'), + buttonImageOnly: true + }); + $('#controls #until:not([readonly])').datepicker(); + // bind usage to the usage icons + $('#dialog-share img.shorty-usage:not(.disabled)').live('click',function(e){Shorty.WUI.Entry.send(e,$(this));}); + // bind actions to the actions icons + $('#list tbody .shorty-actions a').live('click',function(e){Shorty.WUI.Entry.click(e,$(this));}); + // bind highlighting to clicks on a row, except for the action icons + $('#list tbody tr td:not(#actions)').live('click',function(){ + Shorty.WUI.List.highlight($(this).parents('tr')); + Shorty.WUI.Dialog.hide($('.shorty-embedded').eq(0)); + }); + // pretty select boxes where applicable (class controlled) + $('.chosen').chosen(); + // title & target filter reaction + $('#list thead tr#toolbar').find('th#target,th#title').find('#filter').bind('keyup',function(){ + Shorty.WUI.List.filter( + $($(this).context.parentElement.parentElement).attr('id'), + $(this).val() + ); + }); + // status filter reaction + $('#list thead tr#toolbar th#status select').change(function(){ + Shorty.WUI.List.filter( + $(this).parents('th').attr('id'), + $(this).find(':selected').val() + ); + }); + // column sorting reaction + $('#list thead tr#toolbar div img.shorty-sorter').bind('click',function(){ + Shorty.WUI.List.sort($(this).attr('data-sort-code')); + }); +}); // document.ready + diff --git a/apps/shorty/js/list.js b/apps/shorty/js/list.js new file mode 100644 index 00000000000..89f319e2e33 --- /dev/null +++ b/apps/shorty/js/list.js @@ -0,0 +1,39 @@ +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file js/list.js + * @brief Client side desktop initialization for normal calls of the plugin + * @author Christian Reiner + */ + +$(document).ready(function(){ + // initialize desktop + $.when( + Shorty.WUI.Controls.init() + ).then(function(){ + Shorty.WUI.List.build(); + }); +}); // document.ready diff --git a/apps/shorty/js/preferences.js b/apps/shorty/js/preferences.js new file mode 100644 index 00000000000..4cda3ab37ac --- /dev/null +++ b/apps/shorty/js/preferences.js @@ -0,0 +1,69 @@ +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file js/preferences.js + * @brief Client side activity initialization for the user preferences dialog + * @author Christian Reiner + */ + +$(document).ready(function(){ + // backend preferences, activate hints for currently selected backend + var type=$('#shorty #backend-type').val()||''; + if (type.length){ + $('#shorty #backend-'+type).show(); + } + // backend 'static': initialize example that depends on backend-base system setting + if ($('#shorty #backend-static #backend-static-base').val().length) + $('#shorty #backend-static #example').text($('#shorty #backend-static #backend-static-base').val()+'<shorty id>'); + // backend 'static': offer a clickable example link to verify the correct setup + $('#shorty #backend-static #example').bind('click',function(event){ + event.preventDefault(); + Shorty.Action.Setting.verify(); + }); + // react with a matching explanation and example url when backend type is chosen + $('.chosen').chosen(); + $('#shorty #backend-type').change( + function(){ + var type=$('#shorty #backend-type').val(); + $('#shorty .backend-supplement').hide(); + if (type.length){ + $('#shorty .backend-supplement').filter('#backend-'+type).fadeIn('slow'); + // save preference + Shorty.Action.Preference.set($('#shorty #backend-type').serialize()); + return false; + } + } + ); + // safe preferences + $('#shorty .backend-supplement').focusout(function(){ + // save preference + Shorty.Action.Preference.set($(this).find('input').serialize()); + }); + // safe sms-control + $('#shorty #sms-control').change(function(){ + Shorty.Action.Preference.set($('#shorty #sms-control').serialize()); + }); +}); diff --git a/apps/shorty/js/settings.js b/apps/shorty/js/settings.js new file mode 100644 index 00000000000..254ab4f0c13 --- /dev/null +++ b/apps/shorty/js/settings.js @@ -0,0 +1,53 @@ +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file js/settings.js + * @brief Client side activity initialization for the system settings dialog + * @author Christian Reiner + */ + +$(document).ready(function(){ + // initialize example that depends on backend-base + if ($('#shorty #backend-static-base').val().length) + $('#shorty #backend-static #example').text($('#shorty #backend-static-base').val()+'<shorty id>'); + // modify example upon input of a base + $('#shorty #backend-static-base').bind('input',function(){ + $('#shorty #backend-static #example').text($('#shorty #backend-static-base').val()+'<shorty id>'); + }); + // backend 'static': offer a clickable example link to verify the correct setup + $('#shorty #backend-static #example').bind('click',function(event){ + event.preventDefault(); + Shorty.Action.Setting.verify(); + }); + // store setting + $('#shorty #backend-static-base').focusout(function(){ + // modify example + $('#shorty #backend-static #example').text($('#shorty #backend-static-base').val()+'<shorty id>'); + // save setting + Shorty.Action.Setting.set($('#shorty #backend-static-base').serialize()); + return false; + }); +}); diff --git a/apps/shorty/js/shorty.js b/apps/shorty/js/shorty.js new file mode 100644 index 00000000000..688c3e6e158 --- /dev/null +++ b/apps/shorty/js/shorty.js @@ -0,0 +1,1489 @@ +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file js/shorty.js + * @brief Client side activity library + * @author Christian Reiner + */ + +// max()-selector +// usage: var maxWidth = $("a").max(function() {return $(this).width(); }); +$.fn.max = function(selector) { + return Math.max.apply(null, this.map(function(index, el) { return selector.apply(el); }).get() ); +} +// min()-selector +// usage: var minWidth = $("a").min(function() {return $(this).width(); }); +$.fn.min = function(selector) { + return Math.min.apply(null, this.map(function(index, el) { return selector.apply(el); }).get() ); +} + +/** + * @class Shorty + * @brief Central activity library for the client side + * @author Christian Reiner + */ +Shorty = +{ + // ===== Shorty.WUI ===== + WUI: + { + // ===== Shorty.WUI.Controls ===== + Controls: + { + // ===== Shorty.WUI.Controls.init ===== + init: function(){ + if (Shorty.Debug) Shorty.Debug.log("init controls"); + var dfd = new $.Deferred(); + $.when( + Shorty.WUI.Controls.toggle(), + Shorty.WUI.Sums.fill() + ).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.Controls.init + // ===== Shorty.WUI.Controls.toggle ===== + toggle: function(){ + if (Shorty.Debug) Shorty.Debug.log("toggle controls"); + var dfd = new $.Deferred(); + Shorty.WUI.Notification.hide(); + // show or hide dialog + var controls = $('#controls'); + if ( ! controls.is(':visible')){ + $.when( + $.when( + controls.slideDown('slow') + ).done(Shorty.WUI.Sums.fill) + ).done(dfd.resolve) + }else{ + $.when( + controls.slideUp('fast') + ).done(dfd.resolve) + } + return dfd.promise(); + }, // Shorty.WUI.Controls.toggle + }, // Shorty.WUI.Controls + // ===== Shorty.WUI.Desktop ===== + Desktop: + { + // ===== Shorty.WUI.Desktop.show ===== + show: function(duration){ + if (Shorty.Debug) Shorty.Debug.log("show desktop"); + duration = duration || 'slow'; + var dfd = new $.Deferred(); + $.when($('#desktop').fadeTo(duration,1.0)).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.Desktop.show + // ===== Shorty.WUI.Desktop.hide ===== + hide: function(duration){ + if (Shorty.Debug) Shorty.Debug.log("hide desktop"); + duration = duration || 'slow'; + var dfd = new $.Deferred(); + $.when($('#desktop').fadeTo(duration,0.3)).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.Desktop.hide + }, // Shorty.WUI.Desktop + // ===== Shorty.WUI.Dialog ===== + Dialog: + { + // ===== Shorty.WUI.Dialog.execute ===== + execute: function(dialog){ + if (Shorty.Debug) Shorty.Debug.log("execute dialog "+dialog.attr('id')); + var dfd = new $.Deferred(); + switch ( dialog.attr('id') ){ + case 'dialog-add': + $.when( + Shorty.WUI.Notification.hide(), + Shorty.Action.Url.add() + ).done(dfd.resolve) + break; + case 'dialog-edit': + $.when( + Shorty.WUI.Notification.hide(), + Shorty.Action.Url.edit() + ).done(dfd.resolve) + break; + case 'dialog-del': + $.when( + Shorty.WUI.Notification.hide(), + Shorty.Action.Url.del() + ).done(dfd.resolve) + break; + default: + dfd.resolve(); + } // switch + return dfd.promise(); + }, // Shorty.WUI.Dialog.execute + // ===== Shorty.WUI.Dialog.hide ===== + hide: function(dialog){ + if (Shorty.Debug) Shorty.Debug.log("hide dialog "+dialog.attr('id')); + var duration = 'slow'; + var dfd = new $.Deferred(); + if (!dialog.is(':visible')) + dfd.resolve(); + else{ + $.when( + dialog.slideUp(duration) + ).pipe(function(){ + switch ( dialog.attr('id') ){ + case 'dialog-add': + dialog.find('#confirm').unbind('click'); + dialog.find('#target').unbind('focusout'); + break; + default: + } // switch + }).pipe(function(){ + if (dialog.hasClass('shorty-standalone')) + Shorty.WUI.Desktop.show(); + }).done(dfd.resolve) + } + return dfd.promise(); + }, // Shorty.WUI.Dialog.hide + // ===== Shorty.WUI.Dialog.reset ===== + reset: function(dialog){ + if (Shorty.Debug) Shorty.Debug.log("reset dialog "+dialog.attr('id')); + var dfd = new $.Deferred(); + if (dialog){ + // reset dialog fields + $.when( + $.each(dialog.find('#status'),function(){ + if($(this).is('[data]')) + $(this).val($(this).attr('data')); + else $(this).val(''); + }), + $.each(dialog.find('input,textarea'),function(){ + if($(this).is('[data]')) + $(this).val($(this).attr('data')).attr('placeholder',$(this).attr('data')); + else $(this).val('').attr('placeholder',''); + }), + $.each(dialog.find('.shorty-value'),function(){ + if($(this).is('[data]')) + $(this).text($(this).attr('data')); + else $(this).text(''); + }), + $.each(dialog.find('.shorty-icon'), function(){ + if($(this).is('[data]')) + $(this).attr('src',$(this).attr('data')); + else $(this).attr('src',''); + }), + Shorty.WUI.Dialog.sharpen(dialog,false) + ).done(dfd.resolve) + } + else + dfd.resolve(); + return dfd.promise(); + }, // Shorty.WUI.Dialog.reset + // ===== Shorty.WUI.Dialog.sharpen ===== + sharpen: function(dialog,sharpness){ + if (Shorty.Debug) Shorty.Debug.log("toggle sharpness of dialog '"+dialog.attr('id')+"' to "+sharpness); + var confirm=dialog.find('#confirm'); + if (sharpness){ + $('#dialog-add #busy').fadeOut('slow'); + confirm.unbind('click'); + confirm.bind('click',{dialog: dialog}, function(event){event.preventDefault();Shorty.WUI.Dialog.execute(event.data.dialog);}); + confirm.addClass('sharp'); + }else{ + confirm.unbind('click'); + confirm.bind('click',function(event){event.preventDefault();dialog.find('#target').effect('highlight',{'color':'#CCCCCC'},500);}); + confirm.removeClass('sharp'); + } + }, // Shorty.WUI.Dialog.sharpen + // ===== Shorty.WUI.Dialog.show ===== + show: function(dialog){ + if (Shorty.Debug) Shorty.Debug.log("show dialog "+dialog.attr('id')); + var duration = 'slow'; + var dfd = new $.Deferred(); + if (dialog.is(':visible')) + // dialog already open, nothing to do... + dfd.resolve(); + else{ + $('#content form.shorty-dialog').each(function(){ + Shorty.WUI.Dialog.hide($(this)); + }); + // hide 'old' notifications + Shorty.WUI.Notification.hide(), + // some preparations + $.when( + function(){ + var dfd = new $.Deferred(); + if (dialog.hasClass('shorty-standalone')) + $.when(Shorty.WUI.Desktop.hide()).done(dfd.resolve) + else dfd.resolve(); + return dfd.promise(); + }() + ).pipe(function(){ + // prevent submission before entering anything + Shorty.WUI.Dialog.sharpen(dialog,false); + // show dialog + dialog.slideDown(duration); + }).pipe(function(){ + // initialize dialog actions + switch(dialog.attr('id')){ + case 'dialog-add': + dialog.find('#target').focus(); + dialog.find('#target').bind('focusout', {dialog: dialog}, function(event){Shorty.WUI.Meta.collect(event.data.dialog);}); + break; + case 'dialog-edit': + dialog.find('#title').focus(); + Shorty.WUI.Dialog.sharpen(dialog,true); + break; + } // switch + }).done(dfd.resolve) + } + return dfd.promise(); + }, // Shorty.WUI.Dialog.show + // ===== Shorty.WUI.Dialog.toggle ===== + toggle: function(dialog){ + if (Shorty.Debug) Shorty.Debug.log("toggle dialog "+dialog.attr('id')); + var dfd = new $.Deferred(); + Shorty.WUI.Notification.hide(); + // show or hide dialog + if ( ! dialog.is(':visible')) + $.when(Shorty.WUI.Dialog.show(dialog)).done(dfd.resolve) + else + $.when(Shorty.WUI.Dialog.hide(dialog)).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.Dialog.toggle + // ===== Shorty.WUI.Dialog.wipe ===== + wipe: function(dialog){ + if (Shorty.Debug) Shorty.Debug.log("wipe dialog "+dialog.attr('id')); + var dfd = new $.Deferred(); + if (dialog){ + // wipe dialog fields + $.when( + $.each(dialog.find('#status'), function(){$(this).attr('data','blocked');$(this).val('blocked');}), + $.each(dialog.find('input'), function(){$(this).attr('data','');$(this).val('');}), + $.each(dialog.find('textarea'), function(){$(this).attr('data','');$(this).val('');}), + $.each(dialog.find('.shorty-value'),function(){$(this).attr('data','');$(this).text('');}), + $.each(dialog.find('.shorty-icon'), function(){$(this).attr('data','');$(this).attr('src','');}), + Shorty.WUI.Dialog.sharpen(dialog,false) + ).done(dfd.resolve) + } + else + dfd.resolve(); + return dfd.promise(); + }, // Shorty.WUI.Dialog.wipe + }, // Shorty.WUI.Dialog + // ===== Shorty.WUI.Entry ===== + Entry: + { + // ===== Shorty.WUI.Entry.click ===== + click: function(event,element){ + var dfd = new $.Deferred(); + var entry=element.parents('tr').eq(0); + if (Shorty.Debug) Shorty.Debug.log(event.type+" on action "+element.attr('id')+" for entry "+entry.attr('id')); + // + if ($('.shorty-dialog').is(':visible')) + $('.shorty-dialog').each(function(){Shorty.WUI.Dialog.hide($(this));}); + else{ + // highlight clicked row as active entry + $.when( + Shorty.WUI.List.highlight(entry) + ).pipe(function(){ + if ('click'==event.type){ + switch(element.attr('id')){ + case 'del': Shorty.WUI.Entry.del(entry); break; + case 'edit': Shorty.WUI.Entry.edit(entry); break; + case 'open': Shorty.Action.Url.forward(entry); break; + case 'share': Shorty.WUI.Entry.share(entry); break; + case 'show': Shorty.WUI.Entry.show(entry); break; + } // switch + } // if click + }).done(dfd.resolve) + } // else + return dfd.promise(); + }, // Shorty.WUI.Entry.click + // ===== Shorty.WUI.Entry.del ===== + del: function(entry){ + if (Shorty.Debug) Shorty.Debug.log("delete entry "+entry.attr('id')); + if (entry.hasClass('deleted')){ + // change status to deleted + Shorty.Action.Url.status(entry.attr('data-id'),'blocked'); + // mark row as undeleted + entry.removeClass('deleted'); + }else{ + // change status to deleted + Shorty.Action.Url.status(entry.attr('data-id'),'deleted'); + // mark row as deleted + entry.addClass('deleted'); + } + }, // Shorty.WUI.Entry.del + // ===== Shorty.WUI.Entry.edit ===== + edit: function(entry){ + if (Shorty.Debug) Shorty.Debug.log("modify entry "+entry.attr('id')); + var dfd = new $.Deferred(); + // use the existing edit dialog for this + var dialog=$('#controls #dialog-edit'); + // load entry into dialog + dialog.find('#id').val(entry.attr('data-id')); + dialog.find('#status').val(entry.attr('data-status')||''); + dialog.find('#source').val(entry.attr('data-source'||'')); + dialog.find('#target').val(entry.attr('data-target'||'')); + dialog.find('#title').val(entry.attr('data-title')||''); + dialog.find('#clicks').val(entry.attr('data-clicks')||''); + dialog.find('#created').val(entry.attr('data-created')||''); + dialog.find('#accessed').val(entry.attr('data-accessed')||''); + dialog.find('#notes').val(entry.attr('data-notes')||''); +// dialog.find('#until').datepicker('setDate',new Date(entry.attr('data-until'))||''); + dialog.find('#until').datepicker('setDate',new Date(entry.attr('data-until'))||'') + .datepicker('refresh'); + // open edit dialog + Shorty.WUI.Dialog.show(dialog) + $.when( + Shorty.WUI.Meta.get(entry.attr('data-target')) + ).pipe(function(response){ + var meta=response.data; + if (meta.final) + dialog.find('#target').val(meta.final); + dialog.find('#title').attr('placeholder',meta.title); + dialog.find('#meta').fadeTo('fast',0,function(){ + Shorty.WUI.Meta.reset(dialog); + // specify the icons and information to be shown as meta data + dialog.find('#staticon').attr('src',meta.staticon); + dialog.find('#schemicon').attr('src',meta.schemicon); + dialog.find('#favicon').attr('src',meta.favicon); + dialog.find('#mimicon').attr('src',meta.mimicon); + dialog.find('#explanation').html(meta.title?meta.title:'[ '+meta.explanation+' ]'); + dialog.find('#meta').fadeTo('fast',1); + }) + }).done(function(){ + Shorty.WUI.Dialog.sharpen(dialog,true); + dfd.resolve(); + }).fail(function(){ + Shorty.WUI.Dialog.sharpen(dialog,false); + dfd.reject(); + }) + return dfd.promise(); + }, // Shorty.WUI.Entry.edit + // ===== Shorty.WUI.Entry.send ===== + send: function(event,element){ + var dfd = new $.Deferred(); + var action=element.attr('id'); + var entry=element.parents('tr'); + if (Shorty.Debug) Shorty.Debug.log("send action "+action+" on entry "+entry.attr('data-id')); + // take action + $.when( + Shorty.Action.Url.send(action,entry) + ).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.Entry.send + // ===== Shorty.WUI.Entry.share ===== + share: function(entry){ + if (Shorty.Debug) Shorty.Debug.log("share entry "+entry.attr('id')); + var dfd = new $.Deferred(); + // use the existing 'share' dialog for this + var dialog=$('#dialog-share'); + // fill and show dialog + dialog.find('#id').val(entry.attr('data-id')) + .attr('data',entry.attr('data-id')); + dialog.find('#source').attr('href',entry.attr('data-source')) + .text(entry.attr('data-source')); + dialog.find('#relay').attr('href',entry.attr('data-relay')) + .text(entry.attr('data-relay')); + dialog.find('#target').attr('href',entry.attr('data-target')) + .text(entry.attr('data-target')); + dialog.find('#status').attr('value',entry.attr('data-status')) + .attr('data',entry.attr('data-status')); + // move 'share' dialog towards entry + dialog.appendTo(entry.find('td#actions')), + // open dialog + $.when( + Shorty.WUI.Dialog.show(dialog) + ).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.Entry.share + // ===== Shorty.WUI.Entry.show ===== + show: function(entry){ + if (Shorty.Debug) Shorty.Debug.log("show entry "+entry.attr('id')); + var dfd = new $.Deferred(); + // use the existing edit dialog for this + var dialog=$('#controls #dialog-show'); + // load entry into dialog + dialog.find('#id').attr('data-id',entry.attr('data-id')).val(entry.attr('data-id')); + dialog.find('#status').attr('data-status',entry.attr('data-status')||'').val(t('shorty',entry.attr('data-status'))||''); + dialog.find('#source').attr('data-source',entry.attr('data-source')).val(entry.attr('data-source')); + dialog.find('#target').attr('data-target',entry.attr('data-target')).val(entry.attr('data-target')); + dialog.find('#title').attr('data-title',entry.attr('data-title')).val(entry.attr('data-title')); + dialog.find('#until').attr('data-until',entry.attr('data-until')||'').val(entry.attr('data-until')||''); + dialog.find('#clicks').attr('data-clicks',entry.attr('data-clicks')||'').val(entry.attr('data-clicks')||''); + dialog.find('#created').attr('data-created',entry.attr('data-created')||'').val(entry.attr('data-created')||''); + dialog.find('#accessed').attr('data-accessed',entry.attr('data-accessed')||'').val(entry.attr('data-accessed')||''); + dialog.find('#notes').attr('data-notes',entry.attr('data-notes')).val(entry.attr('data-notes')); + // open edit dialog + Shorty.WUI.Dialog.show(dialog) + $.when( + Shorty.WUI.Meta.get(entry.attr('data-target')) + ).pipe(function(response){ + var meta=response.data; + if (meta.final) + dialog.find('#target').val(meta.final); + dialog.find('#title').attr('placeholder',meta.title); + dialog.find('#meta').fadeTo('fast',0,function(){ + Shorty.WUI.Meta.reset(dialog); + // specify the icons and information to be shown as meta data + dialog.find('#staticon').attr('src',meta.staticon); + dialog.find('#schemicon').attr('src',meta.schemicon); + dialog.find('#favicon').attr('src',meta.favicon); + dialog.find('#mimicon').attr('src',meta.mimicon); + dialog.find('#explanation').html(meta.title?meta.title:'[ '+meta.explanation+' ]'); + dialog.find('#meta').fadeTo('fast',1); + }) + }).done(function(){ + dfd.resolve(); + }).fail(function(){ + dfd.reject(); + }) + return dfd.promise(); + } // Shorty.WUI.Entry.show + }, // Shorty.WUI.Entry + // ===== Shorty.WUI.Hourglass ===== + // Shorty.WUI.Hourglass + Hourglass: + { + // ===== Shorty.WUI.Hourglass.toggle ===== + toggle: function(show){ + if (Shorty.Debug) Shorty.Debug.log("toggle hourglass to "+show?"true":"false"); + var dfd = new $.Deferred(); + var hourglass = $('#desktop .shorty-hourglass'); + if (show){ + if (hourglass.is(':visible')) + dfd.resolve(); + else + $.when( + hourglass.fadeIn('fast') + ).done(dfd.resolve) + }else{ + if (!hourglass.is(':visible')) + dfd.resolve(); + else + $.when( + hourglass.fadeOut('slow') + ).done(dfd.resolve) + } + return dfd.promise(); + }, // Shorty.WUI.Hourglass.toggle + }, // Shorty.WUI.Hourglass + // ===== Shorty.WUI.List ===== + List: + { + // ===== Shorty.WUI.List.add ===== + add: function(list,hidden){ + if (Shorty.Debug) Shorty.Debug.log("add entry to list holding "+list.length+" entries"); + var dfd = new $.Deferred(); + // insert list elements (sets) one by one + var row,set; + $.each(list,function(i,set){ + // clone dummy row from list header: dummy is the last row + row = $('#desktop #list thead tr:last-child').eq(0).clone(); + // set row id to entry id + row.attr('id',set.id); + // add attributes to row, as data and value + $.each(['id','status','title','source','relay','target','clicks','created','accessed','until','notes','favicon'], + function(j,aspect){ + if (hidden) + row.addClass('shorty-fresh'); // might lead to a pulsate effect later + // we wrap the cells content into a span tag + var span=$('<span>'); + // enhance row with real set values + if ('undefined'==set[aspect]) + row.attr('data-'+this,''); + else row.attr('data-'+this,set[aspect]); + // fill data into corresponsing column + var title, content, classes=[]; + switch(aspect) + { + case 'favicon': + span.html('<img class="shorty-icon" width="16" src="'+set[aspect]+'">'); + break; + case 'until': + if (null==set[aspect]) + span.text('-never-'); + else{ + span.text(set[aspect]); + if (Shorty.Date.expired(set[aspect])) + row.addClass('shorty-expired'); + } + break; + case 'title': + span.text(set[aspect]); + span.addClass('ellipsis'); + break; + case 'target': + span.text(set[aspect]); + span.attr('title',set[aspect]); + span.addClass('ellipsis'); + break; + case 'status': + if ('deleted'==set[aspect]) + row.addClass('deleted'); +// span.text(set[aspect]); + span.text(t('shorty',set[aspect])); + break; + default: + span.text(set[aspect]); + } // switch + row.find('td#'+aspect).empty().append(span); + }) // each aspect + // insert new row in table + $('#desktop #list tbody').prepend(row); + }) // each + return dfd.promise(); + }, // Shorty.WUI.List.add + // ===== Shorty.WUI.List.build ===== + build: function() + { + if (Shorty.Debug) Shorty.Debug.log("build list"); + var dfd = new $.Deferred(); + // prepare loading + $.when( + Shorty.WUI.Hourglass.toggle(true), + Shorty.WUI.List.dim(false) + ).done(function(){ + // retrieve new entries + $.when( + Shorty.WUI.List.get() + ).pipe(function(response){ + Shorty.WUI.List.fill(response.data); + }).done(function(){ + $.when( + Shorty.WUI.List.show(), + Shorty.WUI.List.dim(true) + ).always(function(){ + Shorty.WUI.Hourglass.toggle(false) + dfd.resolve(); + }) + }).fail(function(){ + dfd.reject(); + }) + }) + return dfd.promise(); + }, // Shorty.WUI.List.build + // ===== Shorty.WUI.List.dim ===== + dim: function(show){ + if (Shorty.Debug) Shorty.Debug.log("dim list to "+(show?"true":"false")); + var duration='slow'; + var dfd =new $.Deferred(); + var list=$('#desktop #list'); + var body=list.find('tbody'); + if (show) + { + var rows=body.find('tr.shorty-fresh'); + Shorty.WUI.List.highlight(rows.eq(0)); + rows.each(function(){ + $(this).removeClass('shorty-fresh'); + $(this).find('td').effect('pulsate'); + }); + $.when( + Shorty.WUI.List.vacuum(), + body.fadeIn(duration) + ).done(dfd.resolve) + }else{ + if (!body.is(':visible')) + dfd.resolve(); + else + { + $.when( + body.fadeOut(duration) + ).done(dfd.resolve) + } + } + return dfd.promise(); + }, // Shorty.WUI.List.dim + // ===== Shorty.WUI.List.empty ===== + empty: function(){ + if (Shorty.Debug) Shorty.Debug.log("empty list"); + var dfd = new $.Deferred(); + // move embedded dialogs back to their safe place in the controls + $('.shorty-embedded').appendTo($('#controls #dialog-show')); + // remove all rows, one by one + $.when( + $('#desktop').find('#list tbody tr').each(function(){ + if(''!=$(this).attr('id')) + $(this).remove(); + }) + ).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.List.empty + // ===== Shorty.WUI.List.fill ===== + fill: function(list){ + if (Shorty.Debug) Shorty.Debug.log("fill list"); + var dfd = new $.Deferred(); + $.when( + Shorty.WUI.Sums.fill(), + Shorty.WUI.List.empty(), + Shorty.WUI.List.add(list,false) + ).pipe( + // filter list + Shorty.WUI.List.filter('target',$('#list thead tr#toolbar th#target #filter').val()), + Shorty.WUI.List.filter('title', $('#list thead tr#toolbar th#title #filter').val()), + Shorty.WUI.List.filter('status',$('#list thead tr#toolbar th#status select :selected').val()) + ).pipe( + // sort list + $.when( + Shorty.Action.Preference.get('list-sort-code') + ).done(function(pref){ + Shorty.WUI.List.sort(pref['list-sort-code']); + }) + ).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.List.fill + // ===== Shorty.WUI.List.filter ===== + filter: function(column,pattern){ + if (Shorty.Debug) Shorty.Debug.log("filter list by column "+column); + var dfd = new $.Deferred(); + $.when( + $('#list tbody tr').filter(function(){ + return (-1==$(this).find('td#'+column+' span').text().toLowerCase().indexOf(pattern.toLowerCase())); + }).addClass('shorty-filtered'), + $('#list tbody tr').not(function(){ + return (-1==$(this).find('td#'+column+' span').text().toLowerCase().indexOf(pattern.toLowerCase())); + }).removeClass('shorty-filtered') + ).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.List.filter + // ===== Shorty.WUI.List.get ===== + get: function(){ + if (Shorty.Debug) Shorty.Debug.log("get list"); + var dfd = new $.Deferred(); + $.when( + $.ajax({ + type: 'GET', + url: OC.filePath('shorty','ajax','list.php'), + cache: false + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ) + ).done(function(response){ + dfd.resolve(response); + }).fail(function(response){ + dfd.reject(response); + }) + return dfd.promise(); + }, // Shorty.WUI.List.get + // ===== Shorty.WUI.List.hide ===== + hide: function(duration){ + if (Shorty.Debug) Shorty.Debug.log("hide list"); + duration = 'slow'; + var dfd = new $.Deferred(); + var list = $('#desktop #list'); + if ( ! list.is(':visible')) + dfd.resolve(); + else + { + $.when( + list.fadeOut(duration) + ).done(dfd.resolve) + } + return dfd.promise(); + }, // Shorty.WUI.List.hide + // ===== Shorty.WUI.List.highlight ===== + highlight: function(entry){ + if (Shorty.Debug) Shorty.Debug.log("highlighting list entry "+entry.attr('id')); + var dfd = new $.Deferred(); + // close any open embedded dialog + $.when( + Shorty.WUI.Dialog.hide($('.shorty-dialog')) + ).pipe(function(){ + // neutralize all rows that might have been highlighted + $('#desktop #list tr').removeClass('clicked'); + entry.addClass('clicked'); + }).always(dfd.resolve); + return dfd.promise(); + }, // Shorty.WUI.List.highlight + // ===== Shorty.WUI.List.modify ===== + modify: function(list,hidden){ + if (Shorty.Debug) Shorty.Debug.log("modify entry in list holding "+list.length+" entries"); + var dfd = new $.Deferred(); + // modify list elements (sets) one by one + var row,set; + $.each(list,function(i,set){ + // select row from list by id + row=$('#desktop #list tbody tr#'+set.id); + // modify attributes in row, as data and value + $.each(['status','title','until','notes'], + function(j,aspect){ + if (set[aspect]){ + // enhance row with actual set values + row.attr('data-'+this,set[aspect]); + if (hidden) row.addClass('shorty-fresh'); + // fill data into corresponsing column + var content, classes=[]; + switch(aspect) + { + case 'until': + if (null==set[aspect]) + content='-never-'; + else{ + content=set[aspect]; + if (Shorty.Date.expired(set[aspect])) + row.addClass('shorty-expired'); + } + break; + case 'title': + classes.push('ellipsis'); + content=set[aspect]; + break; + case 'status': + if ('deleted'==set[aspect]) + row.addClass('deleted'); + content=set[aspect]; + break; + default: + content=set[aspect]; + } // switch + // show modified column immediately or keep it for a later pulsation effect ? + row.find('td').filter('#'+aspect).html('<span class="'+classes.join(' ')+'">'+content+'</span>'); + } // if aspect + }) // each aspect + }) // each entry + return dfd.resolve().promise(); + }, // Shorty.WUI.List.modify + // ===== Shorty.WUI.List.show ===== + show: function(duration){ + if (Shorty.Debug) Shorty.Debug.log("show list"); + duration = 'slow'; + var dfd = new $.Deferred(); + var list = $('#desktop #list'); + if (list.is(':visible')) + dfd.resolve(); + else + { + // list currently not visible, show it + $.when( + list.find('tbody').show(), + list.fadeIn(duration) + ).done(function(){ + dfd.resolve(); + Shorty.WUI.List.vacuum(); + }) + } + return dfd.promise(); + }, // Shorty.WUI.List.show + // ===== Shorty.WUI.List.sort ===== + sort: function(sortCode){ + sortCore = sortCode || 'cd'; + var icon=$('#list thead tr#toolbar th div img[data-sort-code="'+sortCode+'"]'); + var sortCol=icon.parents('th').attr('id'); + var sortDir=icon.attr('data-sort-direction'); + if (Shorty.Debug) Shorty.Debug.log("sorting list column "+sortCol+" "+(sortDir=='asc'?'ascending':'descending')); + // use the 'tinysort' jquery plugin for sorting + switch (sortCol){ + case 'until': + $('#list tbody>tr').tsort('td#until',{order:sortDir}); + break; + default: + $('#list tbody>tr').tsort({attr:'data-'+sortCol,order:sortDir}); + } // switch + // mark currently active sort icon + var icons=$('#list thead tr#toolbar img.shorty-sorter'); + icons.removeClass('shorty-active'); + icons.filter('[data-sort-code="'+sortCode+'"]').addClass('shorty-active'); + // store the sorting code as preference, for returning list retrievals + Shorty.Action.Preference.set({'list-sort-code':sortCode}); + }, // Shorty.WUI.List.sort + // ===== Shorty.WUI.List.toggle ===== + toggle: function(duration){ + if (Shorty.Debug) Shorty.Debug.log("toggle list"); + duration = 'slow'; + var dfd = new $.Deferred(); + if (list.is(':visible')) + return Shorty.WUI.List.hide(); + else + return Shorty.WUI.List.show(); + }, // Shorty.WUI.List.toggle + // ===== Shorty.WUI.List.vacuum ===== + vacuum: function(){ + if (Shorty.Debug) Shorty.Debug.log("vacuum list"); + // list is empty if no row exists + if (0!=$('#list tbody').find('tr').length) + $('#vacuum').fadeOut('fast'); + else + $('#vacuum').fadeIn('slow'); + }, // Shorty.WUI.List.vacuum + // ===== Shorty.WUI.List.Toolbar ===== + Toolbar: + { + // ===== Shorty.WUI.List.Toolbar.toggle ===== + toggle: function(duration){ + if (Shorty.Debug) Shorty.Debug.log("toggle list toolbar"); + duration = duration || 'slow'; + var button=$('#list #tools'); + var toolbar=$('#list #toolbar'); + var dfd = new $.Deferred(); + if (!toolbar.find('div').is(':visible')){ + // tool NOT visible: open toolbar + $.when( + toolbar.find('div').slideDown(duration) + ).pipe( + button.attr('src',button.attr('data-minus')) + ).done(dfd.resolve) + }else{ // toolbar IS visible + // any filters active? prevent closing of toolbar ! + if ( ( (toolbar.find('th#title,#target').find('div input#filter:[value!=""]').length) + &&(toolbar.find('th#title,#target').find('div input#filter:[value!=""]').effect('pulsate')) ) + ||( (toolbar.find('th#status select :selected').val()) +// &&(toolbar.find('#status div.chzn-container').effect('pulsate')) ) + &&(toolbar.find('#status').effect('pulsate')) ) + ) { + if (Shorty.Debug) Shorty.Debug.log('active filter prevents closing of toolbar'); + }else{ + // close toolbar + $.when( + toolbar.find('div').slideUp(duration) + ).pipe( + button.attr('src',button.attr('data-plus')) + ).done(dfd.resolve) + } + } + return dfd.promise(); + }, // Shorty.WUI.List.Toolbar.toggle + }, // Shorty.WUI.List.Toolbar + }, // Shorty.WUI.List + // ===== Shorty.WUI.Notification ===== + Notification: + { + // ===== Shorty.WUI.Notification.hide ===== + hide: function(){ + if (Shorty.Debug) Shorty.Debug.log("hide notification"); + var dfd = new $.Deferred(); + $.when( + $('#notification').slideUp('fast') + ).pipe(function(){ + $('#notification').text(''); + }).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.Notification.hide + // ===== Shorty.WUI.Notification.show ===== + show: function(message,level){ + if (Shorty.Debug) Shorty.Debug.log("show notification with level "+level); + level = level || 'info'; + var dfd = new $.Deferred(); + var duration = 'slow'; + var notification = $('#notification'); + if (message && message.length){ + $.when( + notification.slideUp('fast') + ).done(function(){ + switch(level){ + case 'debug': + // detect debug mode by checking, of function 'debug()' exists + if ( Shorty.Debug ){ + Shorty.Debug.log('Debug: '+message); + $.when( + notification.attr('title', 'debug message'), + notification.text('Debug: '+message), + notification.slideDown(duration) + ).done(dfd.resolve) + } + else + dfd.resolve(); + break; + case 'error': + if (Shorty.Debug) + Shorty.Debug.log('Error: '+message); + $.when( + notification.attr('title', 'error message'), + notification.text('Error: ' + message), + notification.slideDown(duration) + ).done(dfd.resolve) + break; + default: // 'info' + if ( message.length ){ + if (Shorty.Debug) + Shorty.Debug.log('Info: '+message); + $.when( + notification.text(message), + notification.slideDown(duration) + ).done(dfd.resolve) + }else{ + $.when( + notification.text('') + ).done(dfd.resolve) + } + } // switch + }) + } // if message + return dfd.promise(); + }, // Shorty.WUI.Notification.show + }, // Shorty.WUI.Notification + // ===== Shorty.WUI.Meta: ===== + Meta: + { + // ===== Shorty.WUI.Meta.collect ===== + collect: function(dialog){ + if (Shorty.Debug) Shorty.Debug.log("collect meta data"); + var dfd = new $.Deferred(); + var target = $('#dialog-add #target').val().trim(); + // don't bother getting active on empty input + if ( ! target.length ){ + dialog.find('#target').focus(); + dfd.resolve(); + return dfd.promise(); + } + // start expressing activity + $('#dialog-add #busy').fadeIn('fast'); + // fill in fallback protocol scheme 'http' if none is specified + var regexp = /^[a-zA-Z0-9]+\:\//; + if ( ! regexp.test(target) ){ + target = 'http://' + target; + dialog.find('#target').val(target); + } + // query meta data from target + $.when( + Shorty.WUI.Meta.get(target) + ).done(function(response){ + var meta=response.data; + if (meta.final) + dialog.find('#target').val(meta.final); + dialog.find('#title').attr('placeholder',meta.title); + dialog.find('#meta').fadeTo('fast',0,function(){ + Shorty.WUI.Meta.reset(dialog); + // specify the icons and information to be shown as meta data + dialog.find('#staticon').attr('src',meta.staticon); + dialog.find('#schemicon').attr('src',meta.schemicon); + dialog.find('#favicon').attr('src',meta.favicon); + dialog.find('#mimicon').attr('src',meta.mimicon); + dialog.find('#explanation').html(meta.title?meta.title:'[ '+meta.explanation+' ]'); + dialog.find('#meta').fadeTo('fast',1); + Shorty.WUI.Dialog.sharpen(dialog,true); + // stop expressing activity + $('#dialog-add #busy').fadeOut('slow'); + }); + dfd.resolve(response); + }).fail(function(reponse){ + Shorty.WUI.Dialog.sharpen(dialog,false); + dfd.reject(response); + }) + return dfd.promise(); + }, // Shorty.WUI.Meta.collect + // ===== Shorty.WUI.Meta.get ===== + get: function(target){ + if (Shorty.Debug) Shorty.Debug.log("get meta data for target "+target); + var dfd = new $.Deferred(); + $.ajax({ + type: 'GET', + url: OC.filePath('shorty','ajax','meta.php'), + cache: false, + data: { target: encodeURIComponent(target) } + }).pipe( + function(response){return Shorty.Ajax.eval(response);}, + function(response){return Shorty.Ajax.fail(response);} + ).done(function(response){ + dfd.resolve(response); + }).fail(function(response){ + dfd.reject(response); + }) + return dfd.promise(); + }, // Shorty.WUI.Meta.get + // ===== Shorty.WUI.Meta.reset ===== + reset: function(dialog){ + if (Shorty.Debug) Shorty.Debug.log("reset meta data"); + dialog.find('#staticon').attr('src',dialog.find('#staticon').attr('data')); + dialog.find('#schemicon').attr('src',dialog.find('#schemicon').attr('data')); + dialog.find('#favicon').attr('src',dialog.find('#favicon').attr('data')); + dialog.find('#mimicon').attr('src',dialog.find('#mimicon').attr('data')); + dialog.find('#explanation').html(dialog.find('#explanation').attr('data')); + dialog.find('#meta').fadeTo('fast',1); + }, // Shorty.WUI.Meta.reset + }, // Shorty.WUI.Meta + // ===== Shorty.WUI.Sums ===== + Sums: + { + // ===== Shorty.WUI.Sums.fill ===== + fill: function(){ + if (Shorty.Debug) Shorty.Debug.log("fill sums"); + var dfd = new $.Deferred(); + $.when( + // update (set) sum values in the control bar + Shorty.WUI.Sums.get(function(data){ + $('#controls #sum_shortys').text(data.sum_shortys); + $('#controls #sum_clicks').text(data.sum_clicks); + }) + ).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.WUI.Sums.fill + // ===== Shorty.WUI.Sums.get ===== + get: function(callback){ + if (Shorty.Debug) Shorty.Debug.log("get sums"); + var dfd = new $.Deferred(); + $.when( + $.ajax({ + type: 'GET', + url: OC.filePath('shorty','ajax','count.php'), + cache: false, + data: { } + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ) + ).done(function(response){ + if (callback) callback(response.data); + dfd.resolve(response); + }).fail(function(response){ + dfd.reject(response); + }) + return dfd.promise(); + }, // Shorty.WUI.Sums.get + }, // Shorty.WUI.Sums + }, // Shorty.WUI + + //========== + + Action: + { + // ===== Shorty.Action.Preference ===== + Preference: + { + // ===== Shorty.Action.Preference.get ===== + get:function(data){ + if (Shorty.Debug){Shorty.Debug.log("get preference(s):");Shorty.Debug.log(data);} + var dfd = new $.Deferred(); + $.ajax({ + type: 'GET', + url: OC.filePath('shorty','ajax','preferences.php'), + cache: false, + data: data + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ).always(function(response){ + if (Shorty.Debug){Shorty.Debug.log("got preference(s):");Shorty.Debug.log(response.data);} + }).done(function(response){ + dfd.resolve(response.data); + }).fail(function(response){ + dfd.reject({}); + }) + return dfd.promise(); + }, // Shorty.Action.Preference.get + // ===== Shorty.Action.Preference.set ===== + set:function(data){ + if (Shorty.Debug){Shorty.Debug.log("set preference(s):");Shorty.Debug.log(data);} + var dfd = new $.Deferred(); + $.ajax({ + type: 'POST', + url: OC.filePath('shorty','ajax','preferences.php'), + cache: false, + data: data + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ).always(function(response){ + if (Shorty.Debug){Shorty.Debug.log("got preference(s):");Shorty.Debug.log(response.data);} + }).done(function(response){ + dfd.resolve(response.data); + }).fail(function(response){ + dfd.reject({}); + }) + return dfd.promise(); + }, // Shorty.Action.Preference.set + }, // Shorty.Action.Preference + // ===== Shorty.Action.Setting ===== + Setting: + { + // ===== Shorty.Action.Setting.get ===== + get:function(data){ + if (Shorty.Debug){Shorty.Debug.log("get setting(s):");Shorty.Debug.log(data);} + var dfd = new $.Deferred(); + $.ajax({ + type: 'GET', + url: OC.filePath('shorty','ajax','settings.php'), + cache: false, + data: data + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ).always(function(response){ + if (Shorty.Debug){Shorty.Debug.log("got preference(s):");Shorty.Debug.log(response.data);} + }).done(function(response){ + dfd.resolve(response.data); + }).fail(function(response){ + dfd.reject({}); + }) + return dfd.promise(); + }, // Shorty.Action.Setting.get + // ===== Shorty.Action.Setting.set ===== + set:function(data){ + if (Shorty.Debug){Shorty.Debug.log("set setting(s):");Shorty.Debug.log(data);} + var dfd = new $.Deferred(); + $.ajax({ + type: 'POST', + url: OC.filePath('shorty','ajax','settings.php'), + cache: false, + data: data + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ).always(function(response){ + if (Shorty.Debug){Shorty.Debug.log("got preference(s):");Shorty.Debug.log(response.data);} + }).done(function(response){ + dfd.resolve(response.data); + }).fail(function(response){ + dfd.reject({}); + }) + return dfd.promise(); + }, // Shorty.Action.Setting.set + // ===== Shorty.Action.Setting.popup ===== + popup:{}, + // ===== Shorty.Action.Setting.verify ===== + verify:function(){ + if (!Shorty.Action.Setting.popup.dialog){ + Shorty.Action.Setting.popup=$('#shorty #dialog-verification'); + Shorty.Action.Setting.popup.dialog({show:'fade',autoOpen:false,modal:true}); + Shorty.Action.Setting.popup.dialog('option','minHeight',240 ); + } + var dfd = new $.Deferred(); + $.when( + this.check(Shorty.Action.Setting.popup, + $('#shorty #backend-static #backend-static-base').val()) + ).done(dfd.resolve) + return dfd.promise(); + }, // Shorty.Action.Setting.verify + // ===== Shorty.Action.Setting.check ===== + check:function(popup,target){ + popup.find('#verification-target').text(target); + popup.dialog('open'); + popup.find('#success').hide(); + popup.find('#failure').hide(); + popup.find('#hourglass').fadeIn('fast'); + var dfd = new $.Deferred(); + $.ajax({ + // the '0000000000' below is a special id recognized for testing purposes + url: target+'0000000000', + cache: false, + data: { }, + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ).done(function(response){ + $.when( + popup.find('#hourglass').fadeOut('fast') + ).then(function(){ + popup.find('#success').fadeIn('fast'); + dfd.resolve(response); + }) + }).fail(function(response){ + $.when( + popup.find('#hourglass').fadeOut('fast') + ).then(function(){ + popup.find('#failure').fadeIn('fast'); + dfd.reject(response); + }) + }) + return dfd.promise(); + } // Shorty.Action.Setting.check + }, // Shorty.Action.Setting + // ===== Shorty.Action.Url ===== + Url: + { + // ===== Shorty.Action.Url.add ===== + add:function(){ + if (Shorty.Debug) Shorty.Debug.log("action add url"); + var dfd=new $.Deferred(); + var dialog=$('#dialog-add'); + var status=dialog.find('#status').val()||'public'; + var target=dialog.find('#target').val()||''; + var title =dialog.find('#title').val()||''; + var notes =dialog.find('#notes').val()||''; + var until =dialog.find('#until').val()||''; + // store favicon from meta data, except it is the internal default blank + var favicon = dialog.find('#meta #favicon').attr('src'); + favicon=(favicon==dialog.find('#meta #favicon').attr('data'))?'':favicon; + // perform upload of new shorty + $.when( + Shorty.WUI.Notification.hide(), + // close and neutralize dialog + Shorty.WUI.Dialog.hide(dialog), + Shorty.WUI.List.dim(false), + Shorty.WUI.List.show() + ).done(function(){ + var data={status: status, + target: target, + title: title, + notes: notes, + until: until, + favicon: favicon}; + if (Shorty.Debug) Shorty.Debug.log(data); + $.ajax({ + type: 'POST', + url: OC.filePath('shorty','ajax','add.php'), + cache: false, + data: data + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ).done(function(response){ + // wipe entries in dialog + Shorty.WUI.Dialog.reset(dialog) + }).done(function(response){ + // add shorty to existing list + Shorty.WUI.List.add([response.data],true); + Shorty.WUI.List.dim(true) + dfd.resolve(response); + }).fail(function(response){ + Shorty.WUI.List.dim(true) + dfd.reject(response); + }) + }) + return dfd.promise(); + }, // ===== Shorty.Action.Url.add ===== + // ===== Shorty.Action.Url.edit ===== + edit: function(){ + if (Shorty.Debug) Shorty.Debug.log("action modify url"); + var dfd=new $.Deferred(); + var dialog=$('#dialog-edit'); + var id =dialog.find('#id').val(); + var status=dialog.find('#status').val()||'blocked'; + var title =dialog.find('#title').val()||''; + var until =dialog.find('#until').val()||''; + var notes =dialog.find('#notes').val()||''; + // perform modification of existing shorty + $.when( + Shorty.WUI.Notification.hide(), + // close and neutralize dialog + Shorty.WUI.Dialog.hide(dialog), + Shorty.WUI.List.dim(false), + Shorty.WUI.List.show() + ).done(function(){ + var data={id: id, + status: status, + title: title, + notes: notes, + until: until}; + if (Shorty.Debug) Shorty.Debug.log(data); + $.ajax({ + type: 'POST', + url: OC.filePath('shorty','ajax','edit.php'), + cache: false, + data: data, + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ).done(function(response){ + // wipe entries in dialog + Shorty.WUI.Dialog.reset(dialog); + // modify existing entry in list + Shorty.WUI.List.modify([response.data],true); + Shorty.WUI.List.dim(true) + dfd.resolve(response); + }).fail(function(response){ + dfd.reject(response); + }) + }) + return dfd.promise(); + }, // ===== Shorty.Action.Url.edit ===== + // ===== Shorty.Action.Url.del ===== + del: function(){ + if (Shorty.Debug) Shorty.Debug.log("action delete url"); + var dfd = new $.Deferred(); + var dialog = $('#dialog-edit'); + var id = dialog.find('#id').val(); + $.when( +// Shorty.WUI.Notification.hide(), + $.ajax({ + type: 'GET', + url: OC.filePath('shorty','ajax','del.php'), + cache: false, + data: { id: id } + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ) + ).done(function(response){ + // close and neutralize dialog + Shorty.WUI.Dialog.hide(dialog); + // hide and remove deleted entry + // ... + dfd.resolve(response.data); + }).fail(function(response){ + dfd.reject(response.data); + }) + return dfd.promise(); + }, // ===== Shorty.Action.Url.del ===== + // ===== Shorty.Action.Url.forward ===== + forward: function(entry){ + if (Shorty.Debug) Shorty.Debug.log("action forward to entry "+entry.attr('id')); + var url=entry.attr('data-target'); + if (Shorty.Debug) Shorty.Debug.log("opening target url '"+url+"' in new window"); + window.open(url); + }, // Shorty.Action.Url.forward + // ===== Shorty.Action.Url.send ===== + send: function(action,entry){ + if (Shorty.Debug) Shorty.Debug.log("action send via "+action+" with entry "+entry.attr('id')); + switch (action){ + case 'usage-email': + var mailSubject=entry.attr('data-title')||''; + var mailBody=entry.attr('data-notes')+"\n\n"+entry.attr('data-source'); + window.location='mailto:""?' + +'subject='+encodeURIComponent(mailSubject) + +'&body='+encodeURIComponent(mailBody); + break; + case 'usage-sms': + var smsBody=entry.attr('data-title')+" - "+entry.attr('data-notes')+" - "+entry.attr('data-source'); + // unfortunately there is no way to get the body over into the sms application on "sms urls"... + window.prompt(t('shorty',"Copy to clipboard: Ctrl+C, then paste into SMS: Ctrl-V"), smsBody ); + window.location='sms:'; + break; + case 'usage-qrcode': + var title =entry.attr('data-title'); + var source=entry.attr('data-source'); + var target=entry.attr('data-target'); + Shorty.Action.Usage.Dialog.qrcode(title,source,target); + break; + case 'usage-clipboard': + window.prompt(t('shorty',"Copy to clipboard: Ctrl+C"), entry.attr('data-source')); + break; + default: + if (Shorty.Debug) Shorty.Debug.log("usage action '"+action+"' is disabled, refusing to comply"); + } + }, // Shorty.Action.Url.send + // ===== Shorty.Action.Url.show ===== + show: function(){ + var dfd = new $.Deferred(); + var dialog = $('#dialog-show'); + var id = dialog.find('#id').val(); + var record = $(this).parent().parent(); + $('#shorty-add-id').val(record.attr('data-id')); + $('#shorty-add-id').val(record.attr('data-status')); + $('#shorty-add-source').val(record.children('.shorty-source:first').text()); + $('#shorty-add-target').val(record.children('.shorty-target:first').text()); + $('#shorty-add-notes').val(record.children('.shorty-notes:first').text()); + $('#shorty-add-until').val(record.children('.shorty-until:first').text()); + $.when( + function(){ + if ($('.shorty-add').css('display') == 'none'){ + $('.shorty-add').slideToggle(); + } + }, + $('html, body').animate({ scrollTop: $('.shorty-menu').offset().top }, 500) + ).done(dfd.resolve) + return dfd.promise(); + }, // ===== Shorty.Action.Url.show ===== + // ===== Shorty.Action.Url.status ===== + status: function(id,status){ + if (Shorty.Debug) Shorty.Debug.log("changing status of id "+id+" to "+status); + var dfd = new $.Deferred(); + $.ajax({ + type: 'GET', + url: OC.filePath('shorty','ajax','status.php'), + cache: false, + data: { id : id, + status: status } + }).pipe( + function(response){return Shorty.Ajax.eval(response)}, + function(response){return Shorty.Ajax.fail(response)} + ).done(function(){ + // update the rows content + var row=$('#list tbody tr#'+id); + row.attr('data-status',status); + row.find('td#status span').text(t('shorty',status)); + dfd.resolve(); + }).fail(dfd.reject) + return dfd.promise(); + } // Shorty.Action.Url.status + }, // ===== Shorty.Action.Url ===== + // ===== Shorty.Action.Usage ===== + Usage: + { + // ===== Shorty.Action.Usage.Popup ===== + Popup: + { + // ===== Shorty.Action.Usage.Popup.qrcode ===== + qrcode:{}, + }, // Shorty.Action.Usage.Popup + // ===== Shorty.Action.Usage.Dialog ===== + Dialog: + { + // ===== Shorty.Action.Usage.Dialog.qrcode ===== + qrcode:function(title,source,target){ + var qrcode=Shorty.Action.Usage.Popup.qrcode; + if (!qrcode.dialog){ + qrcode=$('#dialog-qrcode'); + qrcode.dialog({show:'fade',autoOpen:false,modal:true}); + qrcode.dialog('option','width',240 ); + //qrcode.dialog('option','height',80 ); + } + // a hidden input field ('qrcode-url') holds the base url to the qrcode generator + // we just add the url parameter for this specific entrys source url + var url=qrcode.find('#qrcode-url').val()+encodeURIComponent(source); + qrcode.dialog('option','title',title); + qrcode.find('#qrcode-img img').attr('src',url).attr('title',source); + qrcode.find('#qrcode-val a').text(url); + qrcode.bind('click',function(){ + qrcode.find('#qrcode-img').toggle(); + qrcode.find('#qrcode-val').toggle(); + }); + qrcode.dialog('open'); + } // Shorty.Action.Usage.Dialog.qrcode + } // Shorty.Action.Usage.Dialog + } // Shorty.Action.Usage + }, // Shorty.Action + + // =========== + + // ===== Shorty.Ajax ===== + Ajax: + { + // ===== Shorty.Ajax.eval ===== + eval:function(response){ + if (Shorty.Debug) Shorty.Debug.log("eval ajax response of status "+response.status); + // Check to see if the response is truely successful. + if (response.status){ + // this is a valid response + if ('success'==response.status){ + Shorty.WUI.Notification.show(response.message,'debug'); + return new $.Deferred().resolve(response); + } else { + Shorty.WUI.Notification.show(response.message,'error'); + return new $.Deferred().reject(response); + } +// }else{ + // TEST (regex) if this is a DB error: + // DB Error: "SQLSTATE[HY000]: General error: 1 near "WHERE": syntax error"..... +// // not a valid response, maybe a DB error ? +// if ('DB error'==response) + } + }, // Shorty.Ajax.eval + + // ===== Shorty.Ajax.fail ===== + fail:function(response){ + if (Shorty.Debug) Shorty.Debug.log("handle ajax failure"); + return new $.Deferred().reject({ + status: 'error', + data: null, + message: [ "Unexpected error: " + response.status + " " + response.statusText ] + }); + } // Shorty.Ajax.fail + }, // Shorty.Ajax + + // ==== Shorty.Date ===== + Date: + { + // ===== Shorty.Date.expired ===== + expired:function(date){ + return (Date.parse(date)<=Date.parse(Date())); + } // Shorty.Date.expired + } // Shorty.Date + +} // Shorty diff --git a/apps/shorty/l10n/de.php b/apps/shorty/l10n/de.php new file mode 100644 index 00000000000..cc4eb624a02 --- /dev/null +++ b/apps/shorty/l10n/de.php @@ -0,0 +1,157 @@ +<?php $TRANSLATIONS = array( +// folder js +"all" => "alle", +"blocked" => "geblockt", +"deleted" => "gelöscht", +"disabled" => "deaktiviert", +"enabled" => "aktiviert", +"never" => "niemals", +"private" => "privat", +"public" => "öffentlich", +"shared" => "geteilt", + +"bitly.com service" => "bitly.com-Service", +"cli.gs service" => "cli.gs-Service", +"goo.gl service" => "goo.gl-Service", +"is.gd service" => "is.gd-Service", +"ti.ny service" => "ti.ny-Service", +"tiny.cc service" => "tiny.cc-Service", +"static backend" => "statisches Backend", + +"Access" => "Zugriff", +"Add a new shorty" => "Neuen Shorty hinzufügen", +"Add as new" => "Neu hinzufügen", +"Add page as 'Shorty' to ownCloud" => "Seite als 'Shorty' zu ownCloud hinzufügen", +"Anything that appears helpful …" => "Alles, was hilfreich erscheint …", +"Backend" => "Backend", +"Base url" => "Basis-Url", +"Choose a service…" => "Wähle einen Dienst…", +"Click for qrcode image" => "Klicken für QRCode-Bild", +"Click for qrcode url" => "Klicken für QRCode-Url", +"Click it, for whatever site you want to create a Shorty." => "Klicke es, für welche Seite auch immer Du ein 'Shorty' generieren willst.", +"Click registered" => "Click registriert", +"Clicks" => "Klicks", +"Close" => "Schließen", +"Copy to clipboard" => "In die Zwischenablage kopieren", +"Copy to clipboard: Ctrl+C" => "In Zwischenablage kopieren: Strg-C", +"Copy to clipboard: Ctrl+C, then paste into SMS: Ctrl-V" => "In Zwischenablage kopieren: Strg-C, dann in SMS einfügen: Strg-V", +"Counted entries and clicks" => "Einträge und Klicks gezählt", +"Creation" => "Generierung", +"Delete shorty" => "Shorty löschen", +"Drag this to your browser bookmarks." => "Zieh' dies in die Lesezeichen Deines Browsers.", +"Example" => "Beispiel", +"Exception" => "Ausnahme", +"Exception (%s)" => "Ausnahme (%s)", +"Expiration" => "Verfall", +"List currently empty." => "Liste derzeit leer.", +"Loading" => "Lade", +"Modifications for shorty with id '%s' saved" => "Änderungen zu Shorty mit Kennung '%s' gespeichert", +"Modify attributes" => "Attribute ändern", +"Modify shorty" => "Shorty ändern", +"New Shorty" => "Neuer Shorty", +"Notes" => "Notizen", +"Number of entries" => "Anzahl der Einträge", +"Number of entries: %s" => "Anzahl der Einträge: %s", +"QRCode" => "QRCode", +"Open source url" => "Quell-Url öffnen", +"Open relay url" => "Relais-Url öffnen", +"Open target" => "Ziel öffnen", +"Open target url" => "Ziel-Url öffnen", +"Preference saved." => "Präferenz gespeichert.", +"Preference(s) retrieved." => "Präferenz(en) abgefragt.", +"Relay url" => "Relais-Url", +"Reload list" => "Liste neu laden", +"Save" => "Speichern", +"Send by email" => "Als E-Mail verschicken", +"Send by SMS" => "Als SMS verschicken", +"Setting saved." => "Einstellung gespeichert.", +"Shortlet" => "Shortlet", +"Shorty with id '%s' deleted" => "Shorty mit Kennung '%s' gelöscht", +"Shorty source url" => "Shorty Quell-Url", +"Shorty title" => "Shorty-Titel", +"Show details" => "Details zeigen", +"Show as QRCode" => "Als QRCode anzeigen", +"Sort ascending" => "aufsteigend sortieren", +"Sort descending" => "absteigend sortieren", +"Source url" => "Quell-Url", +"Specify a backend base url…" => "Lege eine Basis-Url für das Backend fest…", +"Status" => "Status", +"Status change for shorty with id '%s' saved" => "Statusänderung für Shorty mit Kennung '%s' gespeichert", +"Target" => "Ziel", +"Target url" => "Ziel-Url", +"Target url '%s' is valid" => "Ziel-Url '%s' ist valide", +"Test and use" => "Testen und nutzen", +"Title" => "Titel", +"Total of clicks" => "Summe der Klicks", +"Unexpected type of exception caught: %s" => "Unerwarteter Type einer Ausnahme aufgetreten: %s", +"Unknown object of type caught: %s" => "Unbekanntes Objekttyp aufgetreten: %s", +"Url shortened to: %s" => "Url gekürzt zu: %s", +"Verification by click" => "Prüfung durch Klicken", + +"%s\nMessage(code): %s (%s)\nFile(line): %s (%s)\nInfo: %%s" => "%s\Nachricht(Code): %s (%s)\nDatei(Zeile): %s (%s)\nInfo: %%s", + +"API access key" => "API-Zugriffsschlüssel", +"Account" => "Nutzerkonto", +"API key" => "API-Schlüssel", +"bit.ly user" => "bit.ly-Nutzer", +"bit.ly user name" => "bit.ly-Nutzerkennung", +"bit.ly key" => "bit.ly-Schlüssel", +"bit.ly users key" => "bit.ly-Nutzerschlüssel", +"Google API key" => "Google API-Schlüssel", +"Google API account" => "Google API-Nutzerkonto", +"tiny.cc user" => "tiny.cc-Nutzer", +"tiny.cc user name" => "tiny.cc-Nutzerkennung", +"tiny.cc key" => "tiny.cc-Schlüssel", +"tiny.cc user key" => "tiny.cc-Nutzerschlüssel", + +"The external 'bitly.com' service is used to register a short url for each generated shorty." +=> "Der externe 'bitly.com'-Dienst wird genutzt, um eine Kurz-Url für jeden generierten Shorty zu registrieren.", +"This means you have to register an '%s' at their site first." +=> "Das bedeutet, zunächst muss ein '%s' auf deren Seite registriert werden.", +"The external 'turl' service is used to register a short url for each generated shorty." +=> "Der externe 'turl'-Dienst wird genutzt, um eine Kurz-Url für jeden generierten Shorty zu registrieren.", +"The external 'ti.ny' service is used to register a short url for each generated shorty." +=> "Der externe 'ti.ny'-Dienst wird genutzt, um eine Kurz-Url für jeden generierten Shorty zu registrieren.", +"The external 'cli.gs' service is used to register a short url for each generated shorty." +=> "Der externe 'cli.gs'-Dienst wird genutzt, um eine Kurz-Url für jeden generierten Shorty zu registrieren.", +"The external 'is.gd' service is used to register a short url for each generated shorty." +=> "Der externe 'is.gd'-Dienst wird genutzt, um eine Kurz-Url für jeden generierten Shorty zu registrieren.", +"The external 'tiny.cc' service is used to register a short url for each generated shorty." +=>"Der externe 'tiny.cc'-Dienst wird genutzt, um eine Kurz-Url für jeden generierten Shorty zu registrieren.", +"No backend is used, direct links pointing to your ownCloud are generated." +=> "Kein Backend wird verwendet, einfache direkte Links zur ownCloud werden erzeugt.", +"The service requires you to authenticate yourself by providing a valid bit.ly user name and an '%s'." +=> "Dieser Dienst erfordert die Authentifizierung durch eine valide bit.ly-Nutzerkennung und einen '%s'", +"Such links are most likely longer than those generated when using a backend." +=> "Solche Links werden sicherlich länger sein, als wenn ein Backend eingesetzt wird.", +"However this option does not rely on any third party service and keeps your shortys under your control." +=> "Dafür stützt sich diese Option aber nicht auf fremde Angebote und belässt die Shorties unter eigener Kontrolle.", +"A static, rule-based backend is used, shorty links are generated relative to a given base url." +=> "Ein statisches, regelbasiertes Backend wird genutzt, Shorty-Links werden relativ zu einer gegebenen Basis-Url generiert.", +"Since this setup depends on server based configuration rules the base url can only be specified in the 'Admin' section of the configuration." +=> "Da diese Konfiguration von serverseitigen Konfigurationsregeln abhängt, kann die Basis-Url nur unter 'Verwaltung' in der Konfiguration festgelegt werden.", +"You have to take care that any request to the url configured here is internally mapped to the 'shorty' module." +=> "Es muss sicher gestellt werden, dass jede Anfrage an die hier konfigurierte URL intern umgesetzt wird auf das 'Shorty'-Modul", +"Have a try with the example link provided, click it, it should result in a confirmation that your setup is working." +=> "Einfach den verfügbaren Beispiel-Link durch Anklicken testen. Das sollte zu einer Bestätigung führen, dass die Konfiguration funktioniert.", +"Leave empty if you can't provide a short base url that is mapped the described way." +=> "Einfach leer lassen, wenn keine Basis-URL angegeben werden kann, die wir beschrieben umgesetzt wird.", +"Only use this backend, if you can provide a short base url that is mapped the described way. Your shorties won't work otherwise." +=> "Dieses Backend kann nur verwendet werden, wenn die Basis-Url in der beschriebenen Art umgesetzt wird. Die Shorties werden andernfalls nicht nutzbar sein.", +"Googles external 'goo.gl service' is used to register a short url for each generated shorty." +=> "Googles externer 'goo.gl'-Dienst wird genutzt, um eine Kurz-Url für jeden generierten Shorty zu registrieren.", +"You must provide a valid '%s' to use this service." +=> "Es muss eine valide '%s' angegeben werden um diesen Dienst nutzen zu können. ", +"This means you require a 'Google API console account'." +=> "Das bedeutet, dass ein 'Google API console account' benötigt wird", +"Register a new '%s' at their pages." +=> "Einen neuen '%s' auf deren Seite registrieren.", +"Enabling the SMS option will offer sending a Shorty via SMS." +=> "Aktivieren der SMS-Option bietet das Versenden von Shortys via SMS an.", +"Unfortunately support for 'SMS url handling' is usually only found on mobile devices like smart phones." +=> "Unglücklicherweise werden 'SMS-Urls' typischerweise nur auf mobilen Geräten wie etwa Smartphones unterstützt.", +"In addition, the implementations found in Android or iOS are minimalistic, buggy and differ from system to system." +=> "Darüber hinaus sind die Implementierungen, etwa die in Adroid oder auch iOS minimalistisch, fehlerhaft und unterschiedlich von System zu System.", +"In short: this might not work for you, therefore you can disable it…" +=> "Kurz gesagt: die mag nicht funktionieren, daher can die Option deaktiviert werden…", +);
\ No newline at end of file diff --git a/apps/shorty/lib/backend.php b/apps/shorty/lib/backend.php new file mode 100644 index 00000000000..aa6c58b4490 --- /dev/null +++ b/apps/shorty/lib/backend.php @@ -0,0 +1,286 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/backend.php + * Routines to use remote (online) shortening services as backends in a local workflow + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Backend + * @brief Library to register urls using backends, typically remote (online) url shortening services + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Backend +{ + /** + * @method OC_Shorty_Backend::registerUrl + * @brief Wrapper function around the specific backend routines + * @param id (string) Internal shorty id used to reference a shorty upon usage. + * @returns (string) The shortened url as generated by a specific backend. + * @throws OC_Shorty_Exception taking over the explaining of the failure from the specific backend + * @access public + * @author Christian Reiner + */ + static function registerUrl ( $id ) + { + try + { + // construct the $relay, the url to be called to reach THIS service (ownclouds shorty plugin) + $relay = OC_Shorty_Tools::relayUrl ( $id ); + // call backend specific work horse + switch ( $type=OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-type','none') ) + { + default: return OC_Shorty_Backend::registerUrl_default ( $id, $relay ); + case 'static': return OC_Shorty_Backend::registerUrl_static ( $id, $relay ); + case 'bitly': return OC_Shorty_Backend::registerUrl_bitly ( $id, $relay ); + case 'cligs': return OC_Shorty_Backend::registerUrl_cligs ( $id, $relay ); + case 'google': return OC_Shorty_Backend::registerUrl_google ( $id, $relay ); + case 'isgd': return OC_Shorty_Backend::registerUrl_isgd ( $id, $relay ); + case 'tinyurl': return OC_Shorty_Backend::registerUrl_tinyurl ( $id, $relay ); + case 'tinycc': return OC_Shorty_Backend::registerUrl_tinycc ( $id, $relay ); + } // switch + } // try + catch (OC_Shorty_Exception $e) + { + throw $e; + } // catch + catch (Exception $e) + { + throw new OC_Shorty_Exception ( "Failed to register url '%s' at '%s' backend", array($relay,$type) ); + } // catch + } // OC_Shorty_Backend::registerUrl + + /** + * @method OC_Shorty_Backend::registerUrl_default + * @brief Pseudo-registers a given local relay url + * @param id (string) + * @param relay (url) + * @returns validated and pseudo-registered relay + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_default ( $id, $relay ) + { + return OC_Shorty_Type::validate ( $relay, OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_default + + /** + * @method OC_Shorty_Backend::registerUrl_static + * @brief Registers a given local relay url as local static shorty + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_static ( $id, $relay ) + { + if ( (FALSE===($base=trim ( OCP\Config::getAppValue('shorty','backend-static-base',FALSE)))) + ||(empty($base)) ) + throw new OC_Shorty_Exception ( 'No base url defined for the static backend' ); + return OC_Shorty_Type::validate ( $base.$id, OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_static + + /** + * @method OC_Shorty_Backend::registerUrl_bitly + * @brief Registers a given local relay url at the bit.ly shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_bitly ( $id, $relay ) + { + $bitly_api_user = OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-bitly-user',''); + $bitly_api_key = OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-bitly-key', ''); + if ( ! $bitly_api_key || ! $bitly_api_user ) + throw new OC_Shorty_Exception ( 'No API user or key configured' ); + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, 'https://api-ssl.bit.ly/shorten' ); + curl_setopt ( $curl, CURLOPT_SSL_VERIFYHOST, TRUE ); + curl_setopt ( $curl, CURLOPT_POST, TRUE ); + curl_setopt ( $curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json') ); + curl_setopt ( $curl, CURLOPT_POSTFIELDS, json_encode(array('version'=>'2.0.1', + 'longUrl'=>$relay, + 'format'=>'json', + 'login'=>$bitly_api_user, + 'apiKey'=>$bitly_api_key) ) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||(NULL===($payload=json_decode($reply))) + ||(!is_object($payload)) + ||(!property_exists($payload,'id')) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'static'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $payload->id, OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_bitly + + /** + * @method OC_Shorty_Backend::registerUrl_cligs + * @brief Registers a given local relay url at the cli.gs shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_cligs ( $id, $relay ) + { + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, sprintf('http://cli.gs/api/v2/cligs/create?url=%s&appid=owncloud_shorty&test=1', urlencode(trim($relay))) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||( ! preg_match( '/^(.+)$/', $reply, $match )) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'cli.gs'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $match[1], OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_cligs + + /** + * @method OC_Shorty_Backend::registerUrl_isgd + * @brief Registers a given local relay url at the is.gd shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_isgd ( $id, $relay ) + { + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, sprintf('http://is.gd/create.php?format=simple&url=%s', urlencode(trim($relay))) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||( ! preg_match( '/^(.+)$/', $reply, $match )) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'is.gd'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $match[1], OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_isgd + + /** + * @method OC_Shorty_Backend::registerUrl_google + * @brief Registers a given local relay url at the google shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_google ( $id, $relay ) + { + $api_key = OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-google-key',''); + if ( ! $api_key ) + throw new OC_Shorty_Exception ( 'No goo.gl API key configured' ); + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, 'https://www.googleapis.com/urlshortener/v1/url' ); + curl_setopt ( $curl, CURLOPT_SSL_VERIFYHOST, TRUE ); + curl_setopt ( $curl, CURLOPT_POST, TRUE ); + curl_setopt ( $curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json') ); + curl_setopt ( $curl, CURLOPT_POSTFIELDS, json_encode(array('longUrl'=>$relay, + 'key'=>$api_key) ) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||(NULL===($payload=json_decode($reply))) + ||(!is_object($payload)) + ||(!property_exists($payload,'id')) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'goo.gl'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $payload->id, OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_google + + /** + * @method OC_Shorty_Backend::registerUrl_tinycc + * @brief Registers a given local relay url at the tiny.cc shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_tinycc ( $id, $relay ) + { + $api_user = OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-tinycc-user',''); + $api_key = OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-tinycc-key',''); + if ( ! $api_key || ! $api_user ) + throw new OC_Shorty_Exception ( 'No goo.gl API key configured' ); + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, 'http://tiny.cc/?c=shorten' ); + curl_setopt ( $curl, CURLOPT_SSL_VERIFYHOST, TRUE ); + curl_setopt ( $curl, CURLOPT_POST, TRUE ); + curl_setopt ( $curl, CURLOPT_HEADER, TRUE ); + curl_setopt ( $curl, CURLOPT_POSTFIELDS, array('longUrl'=>$relay, + 'version'=>'2.0.3', + 'format'=>'json', + 'login'=>$api_user, + 'apiKey'=>$api_key) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||(NULL===($payload=json_decode($reply))) + ||(!is_object($payload)) + ||(!property_exists($payload,'id')) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'tiny.cc'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $payload->id, OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_google + + /** + * @method OC_Shorty_Backend::registerUrl_tinyurl + * @brief Registers a given local relay url at the tinyURL shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_tinyurl ( $id, $relay ) + { + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, sprintf('http://tinyurl.com/api-create.php?url=%s', urlencode(trim($relay))) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||( ! preg_match( '/^(.+)$/', $reply, $match )) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'tinyUrl'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $match[1], OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_tinyurl + +} // class OC_Shorty_Backend diff --git a/apps/shorty/lib/exception.php b/apps/shorty/lib/exception.php new file mode 100644 index 00000000000..daeb9d10a9c --- /dev/null +++ b/apps/shorty/lib/exception.php @@ -0,0 +1,162 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/exception.php + * Application specific exception class + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Exception + * @brief Application specific exception class + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Exception extends Exception +{ + protected $phrase = ''; + protected $param = array ( ); + + /** + * @method OC_Shorty_Exception::__construct + * @brief: Constructs an exception based on a phrase and a set of parameters + * @param phrase (string) Human readable message that should be translatable + * @param param (array) Set of parameters to be used as sprintf arguments to fill the phrase + * @access public + * @author Christian Reiner + */ + public function __construct ( $phrase, $param=array() ) + { + if ( is_array($param) ) + $this->param = $param; + else $this->param = array($param); + $this->phrase = $phrase; +// $this->message = vsprintf ( $phrase, $this->params ); + Exception::__construct ( vsprintf($phrase,$this->param), 1 ); + } + + /** + * @method OC_Shorty_Exception::getTranslation + * @brief: Returns the translated message of the exception + * @returns (string) Translated message including the filled in set of arguments + * @access public + * @author Christian Reiner + */ + public function getTranslation ( ) + { + return OC_Shorty_L10n::t ( $this->phrase, $this->param ); + } + + /** + * @method OC_Shorty_Exception::JSONerror + * @brief Calls OCP\JSON::error with a pretty formated version of an exception + * @param e (exception) an exception object holding information + * @returns (json) OCP\JSON::error + * @access public + * @author Christian Reiner + */ + static function JSONerror ( $e ) + { + $title = OC_Shorty_L10n::t("Exception"); + switch ( get_class($e) ) + { + case 'OC_Shorty_Exception': + $message = $e->getTranslation(); + break; + case 'PDOException': + $message = sprintf ( OC_Shorty_L10n::t( "%s\nMessage(code): %s (%s)\nFile(line): %s (%s)\nInfo: %%s", + OC_Shorty_L10n::t("Exception (%s)", get_class($e)), + htmlspecialchars($e->getMessage()), + htmlspecialchars($e->getCode()), + htmlspecialchars($e->getFile()), + htmlspecialchars($e->getLine()) ), + (method_exists($e,'errorInfo') ? trim($e->errorInfo()) : '-/-') ); + break; + default: + if ( is_a($e,'Exception') ) + $message = OC_Shorty_L10n::t("Unexpected type of exception caught: %s", get_class($e)); + else $message = OC_Shorty_L10n::t("Unknown object of type caught: %s", get_class($e)); + } // switch + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + $output = trim ( OC_Shorty_Tools::ob_control(FALSE) ); + if ( $output ) + { + $message = "! Swallowing accidential output from ajax routines ! \n" + ."Please fix this ! Here is the first line: \n" + .substr ( $output, 0, strpos($output,"\n") ); + OCP\Util::writeLog( 'shorty', $message, OC_Log::WARN ); + } // output + // return a clean JSON error + return OCP\JSON::error ( array ( 'title' => $title, + 'message' => sprintf("%s: %s", $title, $message) ) ); + } // function error +} // class OC_Shorty_Exception + +/** + * @class OC_Shorty_HttpException + * @brief Application specific exception class: protocol layer + * @access public + * @author Christian Reiner + */ +class OC_Shorty_HttpException extends OC_Shorty_Exception +{ + + /** + * @method OC_Shorty_HttpException::__construct + * @brief: Constructs an exception based on a phrase and a set of parameters + * @param status (integer) Http status code + * @access public + * @author Christian Reiner + */ + public function __construct ( $status ) + { + if ( is_numeric($status) + && array_key_exists($status,OC_Shorty_Type::$HTTPCODE) ) + { + $status = intval($status); + $phrase = OC_Shorty_Type::$HTTPCODE[$status]; + } + else + { + $status = 400; + $phrase = OC_Shorty_Type::$HTTPCODE[400]; // "Bad Request" + } // switch + + // return http status code to client (browser) + if ( ! headers_sent() ) + { + header ( sprintf("HTTP/1.0 %s %s",$status,$phrase) ); + } + $tmpl = new OCP\Template("shorty", "tmpl_http_status", "guest"); + $tmpl->assign("explanation", OC_Shorty_L10n::t($phrase)); + $tmpl->printPage(); + exit; + } // function __construct + +} // class OC_Shorty_HttpException + +?> diff --git a/apps/shorty/lib/hooks.php b/apps/shorty/lib/hooks.php new file mode 100644 index 00000000000..6ba59eccbda --- /dev/null +++ b/apps/shorty/lib/hooks.php @@ -0,0 +1,64 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/hooks.php + * Static class providing routines to populate hooks called by other parts of ownCloud + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Hooks + * @brief Static 'namespace' class for api hook population + * ownCloud propagates to use static classes as namespaces instead of OOP. + * This 'namespace' defines routines to populate hooks called by other parts of ownCloud + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Hooks +{ + /** + * @brief Deletes all Shortys and preferences of a certain user + * @param paramters (array) parameters from postDeleteUser-Hook + * @return bool + */ + public static function deleteUser ( $parameters ) + { + OCP\Util::writeLog ( 'user post delete','wiping all users Shortys', OCP\Util::INFO ); + $result = TRUE; + $param = array ( 'user' => OCP\User::getUser() ); + // wipe shortys + $query = OCP\DB::prepare ( OC_Shorty_Query::WIPE_SHORTYS ); + if ( FALSE===$query->execute($param) ) + $result = FALSE; + // wipe preferences + $query = OCP\DB::prepare ( OC_Shorty_Query::WIPE_PREFERENCES ); + if ( FALSE===$query->execute($param) ) + $result = FALSE; + // report completion success + return $result; + } +} diff --git a/apps/shorty/lib/l10n.php b/apps/shorty/lib/l10n.php new file mode 100644 index 00000000000..648130645a0 --- /dev/null +++ b/apps/shorty/lib/l10n.php @@ -0,0 +1,93 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/l10n.php + * Translation singleton + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_L10n + * @brief Convenient translation singleton + * @access public + * @author Christian Reiner + */ +class OC_Shorty_L10n +{ + /** + * @var OC_Shorty_L10n::dictionary + * @brief An internal dictionary file filled from the translation files provided. + * @access private + * @author Christian Reiner + */ + private $dictionary; + + /** + * @var OC_Shorty_L10n::instance + * @brief Internal singleton object + * @access private + * @author Christian Reiner + */ + static private $instance=NULL; + + /** + * @method OC_Shorty_L10n::__construct + * @brief + * @access private + * @author Christian Reiner + */ + private function __construct ( ) { $this->dictionary = new OC_L10n('shorty'); } + + /** + * @method OC_Shorty_L10n::t + * @brief Translates a given string into the users session language and fills any placeolders + * @param phrase to be translated + * @param … further arguments used as filling tokens in the tradition of printf strategies + * @returns translated phrase or the original phrase incase no translation could be found + * @access public + * @author Christian Reiner + */ + static public function t ( $phrase ) + { + // create singleton instance, if required + if ( ! self::$instance ) + self::$instance = new OC_Shorty_L10n ( ); + // handle different styles of how arguments can be handed over to this method + switch ( func_num_args() ) + { + case 1: return self::$instance->dictionary->t ( $phrase, array() ); + case 2: $arg = func_get_arg(1); + if ( is_array($arg) ) + return self::$instance->dictionary->t ( $phrase, $arg ); + else return self::$instance->dictionary->t ( $phrase, array($arg) ); + default: $args = func_get_args(); + array_shift ( $args ); + return self::$instance->dictionary->t ( $phrase, $args ); + } + } +} // class OC_Shorty_L10n +?> diff --git a/apps/shorty/lib/meta.php b/apps/shorty/lib/meta.php new file mode 100644 index 00000000000..91937bd3c8a --- /dev/null +++ b/apps/shorty/lib/meta.php @@ -0,0 +1,213 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/meta.php + * Routines to retrieve meta information about a remote url + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Meta + * @brief Static 'namespace' class for url meta information retrieval + * ownCloud propagates to use static classes as namespaces instead of OOP. + * This 'namespace' defines routines for the retrieval of meta information about remote urls. + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Meta +{ + + /** + * @method OC_Shorty_Meta::fetchMetaData + * @brief Retrieves the meta information to a given remote url + * @param url decoded target url for which meta information if requested + * @returns associative array holding the requested meta data + * @access public + * @author Christian Reiner + */ + static function fetchMetaData ( $url ) + { + $url_token = parse_url ( $url ); + // some sane fallback values, in case we cannot get the meta data + $meta = array(); + $meta['target'] = $url; + $meta['title'] = strtolower ( $url_token['host'] ); + $meta['scheme'] = strtolower ( $url_token['scheme'] ); + $meta['mimetype'] = 'application/octet-stream'; + $meta['schemicon'] = self::selectIcon ( 'scheme', strtolower($url_token['scheme']) ); + // we wont bother retrieving data about other protocols than http or ftp + if ( ! in_array(strtolower($url_token['scheme']),array('http','https','ftp','ftps')) ) + return $meta; + // to fetch meta data we rely on curl being installed + if ( ! function_exists('curl_init') ) + return $meta; + // try to retrieve the meta data + $handle = curl_init ( ); + curl_setopt ( $handle, CURLOPT_URL, $url ); + curl_setopt ( $handle, CURLOPT_RETURNTRANSFER, 1 ); + curl_setopt ( $handle, CURLOPT_FOLLOWLOCATION, TRUE ); + curl_setopt ( $handle, CURLOPT_MAXREDIRS, 10 ); + if ( FALSE!==($page=curl_exec($handle)) ) + { + // try to extract title from page + preg_match ( "/<head>.*<title>(.*)<\/title>.*<\/head>/si", $page, $match ); + $meta['title'] = htmlspecialchars_decode ( $match[1] ); + $meta['staticon'] = self::selectIcon ( 'state', TRUE ); + // final url after a possible redirection + $meta['final'] = curl_getinfo ( $handle, CURLINFO_EFFECTIVE_URL ); + // try to extract favicon from page + preg_match ( '/<[^>]*link[^>]*(rel=["\']icon["\']|rel=["\']shortcut icon["\']) .*href=["\']([^>]*)["\'].*>/iU', $page, $match ); + if (1<sizeof($match)) + { + // the specified uri might be an url, an absolute or a relative path + // we have to turn it into an url to be able to display it out of context + $favicon = htmlspecialchars_decode ( $match[2] ); + // test for an url + if (parse_url($favicon,PHP_URL_SCHEME)) + { + $meta['favicon'] = $favicon; + } + // test for an absolute path + elseif ( 0===strpos(parse_url($favicon,PHP_URL_PATH),'/') ) + { + $url_token = parse_url($meta['final']); + $meta['favicon'] = sprintf( '%s://%s/%s', $url_token['scheme'], $url_token['host'], $favicon ); + } + // so it appears to be a relative path + else + { + $url_token = parse_url($meta['final']); + $meta['favicon'] = sprintf( '%s://%s%s%s', $url_token['scheme'], $url_token['host'], dirname($url_token['path']), $favicon ); + } + } + $meta['mimetype'] = preg_replace ( '/^([^;]+);.*/i', '$1', curl_getinfo($handle,CURLINFO_CONTENT_TYPE) ); + $meta['mimicon'] = self::selectIcon ( 'mimetype', $meta['mimetype'] ); + $meta['code'] = curl_getinfo ( $handle, CURLINFO_HTTP_CODE ); + $meta['status'] = OC_Shorty_L10n::t ( self::selectCode('status',$meta['code']) ); + $meta['explanation'] = OC_Shorty_L10n::t ( self::selectCode('explanation',$meta['code']) ); + } + curl_close ( $handle ); + // that's it ! + return $meta; + } // function fetchMetaData + + /** + * @method OC_Shorty_Meta::selectCode + * @brief Some helper utility used to resolve numeric http status codes into human readable strings + * @param aspect a string indicating a section/pool a code is to be resolved in + * @param identifier a string indicating a specific code to be resolved + * @returns a human readable string resolving the specified numeric status code + * @throws OC_Shorty_Exception in case of an undefined code to be resolved + * @access public + * @author Christian Reiner + */ + static function selectCode ( $aspect, $identifier ) + { + // map of official http status codes + $_code_map = array + ( + 'status' => OC_Shorty_Type::$HTTPCODE, + 'explanation' => array + ( + 200 => 'Target url is valid and resolved.', + 201 => 'The request has been fulfilled and created a new ressource.', + 202 => 'The request has been accepted.', + 203 => 'The request yielded in non-authorative information.', + 204 => 'The request has been fulfilled but not produced any content.', + 205 => 'The request has been fulfilled and the view should be reset.', + 206 => 'The request has been fulfilled partially.', + ) + ); + // resolve specified code against map or provide some fallback content + if ( key_exists($aspect,$_code_map) && key_exists($identifier,$_code_map[$aspect]) ) + return $_code_map[$aspect][$identifier]; + else + { + switch ( $aspect ) + { + case 'status': return sprintf("Status %s [unknown]",$identifier); + case 'explanation': return sprintf("[Undefined status code '%s']",$identifier); + default: throw new OC_Shorty_Exception ( "unknown aspect '%s' requested to resolve code '%s'", + array($aspect,$identifier) ); + } // switch + } + } // function selectCode + + /** + * @method OC_Shorty_Meta::selectIcon + * @brief Some helper utility for the easy integrate of icon references into templates and alike + * @param aspect a string indicating a section/pool an icon is to be chosen from + * @param identifier a string indicating a specific icon to be referenced + * @returns a hyper reference to an icon in form of a string + * @access public + * @author Christian Reiner + */ + static function selectIcon ( $aspect, $identifier ) + { + switch ( $aspect ) + { + case 'state': + switch ($identifier) + { + case TRUE: return OCP\Util::imagePath('shorty', 'status/good.png'); + case FALSE: return OCP\Util::imagePath('shorty', 'status/bad.png'); + default: return OCP\Util::imagePath('shorty', 'status/neutral.png'); + } // switch identifier + case 'scheme': + switch ($identifier) + { + case 'http': + case 'https': return OCP\Util::imagePath('shorty', 'scheme/H.png'); + case 'ftp': + case 'ftps': return OCP\Util::imagePath('shorty', 'scheme/F.png'); + case 'sftp': return OCP\Util::imagePath('shorty', 'scheme/S.png'); + case 'mailto': return OCP\Util::imagePath('shorty', 'scheme/M.png'); + case 'gopher': return OCP\Util::imagePath('shorty', 'scheme/G.png'); + case 'webdav': + case 'webdavs': return OCP\Util::imagePath('shorty', 'scheme/W.png'); + default: return OCP\Util::imagePath('shorty', 'blank.png'); + } // switch identifier + case 'mimetype': + $identifier = explode('/',$identifier); + switch ($identifier[0]) + { + case 'audio': return OCP\Util::imagePath('core', 'filetypes/audio.png'); + case 'text': return OCP\Util::imagePath('core', 'filetypes/text.png'); + case 'video': return OCP\Util::imagePath('core', 'filetypes/video.png'); + case 'application': + switch ($identifier[1]) + { + case 'pdf': return OCP\Util::imagePath('core', 'filetypes/application-pdf.png'); + default: return OCP\Util::imagePath('shorty', 'blank.png'); + } // switch identifier[1] + default: return OCP\Util::imagePath('shorty', 'blank.png'); + } // switch identifier[0] + } // switch aspect + } // function selectIcon + +} // class OC_Shorty_Meta +?> diff --git a/apps/shorty/lib/query.php b/apps/shorty/lib/query.php new file mode 100644 index 00000000000..6501a54d927 --- /dev/null +++ b/apps/shorty/lib/query.php @@ -0,0 +1,57 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/query.php + * Static catalog of sql queries + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Query + * @brief Static catalog of sql queries + * These query templates are referenced by a OC_Shorty_Query::URL_... + * They have to be prapared by adding an array of parameters + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Query +{ + const URL_INSERT = "INSERT INTO *PREFIX*shorty (id,status,favicon,title,source,target,user,until,created,notes) VALUES (:id,:status,:favicon,:title,:source,:target,:user,:until,CURRENT_DATE,:notes)"; + const URL_DELETE = "DELETE FROM *PREFIX*shorty WHERE user=:user AND id=:id"; + const URL_REMOVE = "DELETE FROM *PREFIX*shorty WHERE user=:user AND 'deleted'=status"; + const URL_UPDATE = "UPDATE *PREFIX*shorty SET status=:status,title=:title,until=:until,notes=:notes WHERE user=:user AND id=:id"; + const URL_STATUS = "UPDATE *PREFIX*shorty SET status=:status WHERE user=:user AND id=:id"; + const URL_CLICK = "UPDATE *PREFIX*shorty SET accessed=CURRENT_TIMESTAMP, clicks=(clicks+1) WHERE id=:id"; + const URL_FORWARD = "SELECT user,source,target,status,(until IS NOT NULL AND until!='' AND until<CURRENT_TIMESTAMP) AS expired FROM *PREFIX*shorty WHERE id=:id"; + const URL_SOURCE = "SELECT id,source,target,status,(until IS NOT NULL AND until!='' AND until<CURRENT_TIMESTAMP) AS expired FROM *PREFIX*shorty WHERE source=:source"; + const URL_VERIFY = "SELECT id,status,favicon,title,source,target,clicks,created,accessed,until,notes FROM *PREFIX*shorty WHERE user=:user AND id=:id LIMIT 1"; + const URL_LIST = "SELECT id,status,favicon,title,source,target,clicks,created,accessed,until,notes FROM *PREFIX*shorty WHERE user=:user ORDER BY :sort"; + const URL_COUNT = "SELECT count(*) AS sum_shortys,IFNULL(sum(clicks),0) AS sum_clicks FROM *PREFIX*shorty WHERE user=:user"; + const WIPE_SHORTYS = "DELETE FROM *PREFIX*shorty WHERE user=:user"; + const WIPE_PREFERENCES = "DELETE FROM *PREFIX*preferences WHERE user=:user"; +} // class OC_Shorty_Query +?> diff --git a/apps/shorty/lib/tools.php b/apps/shorty/lib/tools.php new file mode 100644 index 00000000000..2b3bac70672 --- /dev/null +++ b/apps/shorty/lib/tools.php @@ -0,0 +1,235 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/tools.php + * A collection of general utility routines + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Tools + * @brief Collection of a few practical routines, a tool box + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Tools +{ + // internal flag indicating if output buffering should be used to prevent accidentially output during ajax requests + static $ob_usage = TRUE; + // internal flag indicating if there is currently an output buffer active + static $ob_active = FALSE; + + /** + * @method OC_Shorty_Tools::ob_control + * @param on (boolean) wether to activate or deactivate the buffer + * @access public + * @author Christian Reiner + */ + static function ob_control ( $on=TRUE ) + { + $output = NULL; + if ( self::$ob_usage ) + { + // attempt to use outpout buffering + if ( $on ) + { + // start buffering if possible and not yet started before + if ( function_exists('ob_start') // output buffers installed at all ? + && ! self::$ob_active ) // don't stack buffers (create buffer only, if not yet started) + { + ob_implicit_flush ( FALSE ); + ob_start ( ); + self::$ob_active = TRUE; + } + } // if $on==TRUE + else + { + // end buffering _if_ it has been started before + if ( self::$ob_active ) + { + $output = ob_get_contents ( ); + ob_end_clean ( ); + self::$ob_active = FALSE; + } + } // if $on==FALSE + } // if ob_usage + return $output; + } // function ob_control + + /** + * @method OC_Shorty_Tools::db_escape + * @brief escape a value for incusion in db statements + * @param value (string) value to be escaped + * @returns (string) escaped string value + * @throws OC_Shorty_Exception in case of an unknown database engine + * @access public + * @author Christian Reiner + * @todo use mdb2::quote() / mdb2:.escape() instead ? + */ + static function db_escape ( $value ) + { + $type = OCP\Config::getSystemValue ( 'dbtype', 'sqlite' ); + switch ( $type ) + { + case 'sqlite': + case 'sqlite3': + return sqlite_escape_string ( $value ); + case 'pgsql': + return pg_escape_string ( $value ); + case 'mysql': + if (get_magic_quotes_gpc()) + return mysql_real_escape_string ( stripslashes($value) ); + else return mysql_real_escape_string ( $value ); + } + throw new OC_Shorty_Exception ( "unknown database backend type '%1'", array($type) ); + } // function db_escape + + /** + * @method OC_Shorty_Tools::db_timestamp + * @brief current timestamp as required by db engine + * @returns (string) current timestamp as required by db engine + * @throws OC_Shorty_Exception in case of an unknown database engine + * @access public + * @author Christian Reiner + * @todo not really required any more, we rely on CURRENT_TIMESTAMP instead + */ + static function db_timestamp ( ) + { + $type = OCP\Config::getSystemValue( "dbtype", "sqlite" ); + switch ( $type ) + { + case 'sqlite': + case 'sqlite3': return "strftime('%s','now')"; + case 'mysql': return 'UNIX_TIMESTAMP()'; + case 'pgsql': return "date_part('epoch',now())::integer"; + } + throw new OC_Shorty_Exception ( "unknown database backend type '%1'", array($type) ); + } // function db_timestamp + + /** + * @method OC_Shorty_Tools::shorty_id + * @brief Creates a unique id to be used for a new shorty entry + * @returns (string) valid and unique id + * @access public + * @author Christian Reiner + */ + static function shorty_id ( ) + { + // each shorty installation uses a (once self generated) 62 char alphabet + $alphabet=OCP\Config::getAppValue('shorty','id-alphabet'); + if ( empty($alphabet) ) + { + $alphabet = self::randomAlphabet(62); + OCP\Config::setAppValue ( 'shorty', 'id-alphabet', $alphabet ); + } + // use alphabet to generate a id being unique over time + return self::convertToAlphabet ( str_replace(array(' ','.'),'',microtime()), $alphabet ); + } // function shorty_id + + /** + * + */ + static function randomAlphabet ($length) + { + if ( ! is_integer($length) ) + return FALSE; + $c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxwz0123456789"; + for($l=0;$l<$length;$l++) $s .= $c{rand(0,strlen($c))}; + return str_shuffle($s); + } // function randomAlphabet + + /** + * @method OC_Shorty_Tools::convertToAlphabet + * @brief Converts a given decimal number into an arbitrary base (alphabet) + * @param number decimal value to be converted + * @returns (string) converted value in string notation + * @access public + * @author Christian Reiner + */ + static function convertToAlphabet ( $number, $alphabet ) + { + $alphabetLen = strlen($alphabet); + $decVal = (int) $number; + $number = FALSE; + $nslen = 0; + $pos = 1; + while ($decVal > 0) + { + $valPerChar = pow($alphabetLen, $pos); + $curChar = floor($decVal / $valPerChar); + if ($curChar >= $alphabetLen) + { + $pos++; + } else { + $decVal -= ($curChar * $valPerChar); + if ($number === FALSE) + { + $number = str_repeat($alphabet{1}, $pos); + $nslen = $pos; + } + $number = substr($number, 0, ($nslen - $pos)) . $alphabet{$curChar} . substr($number, (($nslen - $pos) + 1)); + $pos--; + } + } + if ($number === FALSE) $number = $alphabet{1}; + return $number; + } + + /** + * @method OC_Shorty_Tools::relayUrl + * @brief Generates a relay url for a given id acting as a href target for all backends + * @param id (string) shorty id as shorty identification + * @returns (string) generated absolute relay url + * @access public + * @author Christian Reiner + */ + static function relayUrl ($id) + { + return sprintf ( '%s?service=%s&id=%s', OCP\Util::linkToAbsolute("", "public.php"), 'shorty_relay', $id ); + } // function relayUrl + + /** + * @method OC_Shorty_Tools::countShortys + * @brief Returns the total number of entries and clicks from the database + * @returns (array) two elements sum_shortys & sum_clicks holding an integer each + * @access public + * @author Christian Reiner + */ + static function countShorties () + { + $param = array + ( + ':user' => OCP\User::getUser ( ), + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_COUNT ); + $result = $query->execute($param); + $reply = $result->fetchAll(); + return $reply[0]; + } // function countShorties + +} // class OC_Shorty_Tools +?> diff --git a/apps/shorty/lib/type.php b/apps/shorty/lib/type.php new file mode 100644 index 00000000000..97cbf04ddb4 --- /dev/null +++ b/apps/shorty/lib/type.php @@ -0,0 +1,291 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/type.php + * Type handling, recognition and verification routines + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Type + * @brief Static 'namespace' class offering routines and constants used to handle type recognition and value verification + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Type +{ + // the 'types' of values we deal with, actually more something like flavours + const ID = 'id'; + const STATUS = 'status'; + const SORTKEY = 'sortkey'; + const SORTVAL = 'sortval'; + const STRING = 'string'; + const URL = 'url'; + const INTEGER = 'integer'; + const FLOAT = 'float'; + const DATE = 'date'; + const TIMESTAMP = 'timestamp'; + // a list of all valid list sorting codes + static $SORTING = array ( + '' =>'created DESC', // default + 'aa'=>'accessed', 'ad'=>'accessed DESC', + 'ca'=>'created', 'cd'=>'created DESC', + 'da'=>'until', 'dd'=>'until DESC', + 'ha'=>'clicks', 'hd'=>'clicks DESC', + 'ka'=>'id', 'kd'=>'id DESC', + 'sa'=>'status', 'sd'=>'status DESC', + 'ta'=>'title', 'td'=>'title DESC', + 'ua'=>'target', 'ud'=>'target DESC' ); + // a list of all valid user preferences + static $PREFERENCE = array ( + 'backend-type' => OC_Shorty_Type::STRING, + 'backend-static-base' => OC_Shorty_Type::URL, + 'backend-bitly-user' => OC_Shorty_Type::STRING, + 'backend-bitly-key' => OC_Shorty_Type::STRING, + 'backend-google-key' => OC_Shorty_Type::STRING, + 'backend-tinycc-user' => OC_Shorty_Type::STRING, + 'backend-tinycc-key' => OC_Shorty_Type::STRING, + 'sms-control' => OC_Shorty_Type::STRING, + 'list-sort-code' => OC_Shorty_Type::SORTKEY, + ); + // valid status for entries + static $STATUS = array ( + 'blocked', + 'private', + 'shared', + 'public', + 'deleted', + ); + // a list of implemented backends + static $BACKENDS = array ( + 'none' => ' [ none ] ', + 'static' => 'static backend', +// 'bitly' => 'bitly.com service', +// 'cligs' => 'cli.gs service', + 'isgd' => 'is.gd service', + 'google' => 'goo.gl service', +// 'tinycc' => 'tiny.cc service', + 'tinyurl' => 'ti.ny service', + ); + // a list of all valid system settings + static $SETTING = array ( + 'backend-static-base' => OC_Shorty_Type::URL, + ); + static $HTTPCODE = array ( + 200 => 'Ok', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => '(unused)', + 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', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + ); + + /** + * @method OC_Shorty_Type::validate + * @brief Validates a given value against a type specific regular expression + * Validates a given value according to the claimed type of the value. + * Validation is done by matching the value against a type specific regular expression. + * @param value the value to be verified according to the specified type + * @param type the type the value is said to belong to, important for verification + * @param strict flag indicating if the verification should be done strict, that is if an exception should be thrown in case of a failure + * @returns the value itself in case of a positive validation, NULL or an exception in case of a failure, depending on the flag indication strict mode + * @throws error indicating a failed validation in case of strict mode + * @access public + * @author Christian Reiner + */ + static function validate ( $value, $type, $strict=FALSE ) + { + switch ( $type ) + { + case self::ID: + if ( preg_match ( '/^[a-z0-9]{2,20}$/i', $value ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::STATUS: + if ( in_array($value,OC_Shorty_Type::$STATUS) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::SORTKEY: + if ( array_key_exists ( trim($value), self::$SORTING ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::SORTVAL: + if ( in_array ( trim($value), self::$SORTING ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::STRING: + if ( preg_match ( '/^.*$/x', str_replace("\n","\\n",$value) ) ) + return str_replace("\n","\\n",$value); + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::URL: +// $pattern = '/^([a-zA-Z][a-zA-Z][a-zA-Z0-9]+)\:\/\/([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(\/($|[a-zA-Z0-9\.\;\:\,\@\?\'\\\+&%\$#\=~_\-]+)?)*$/'; + $pattern = '/^([a-zA-Z][a-zA-Z][a-zA-Z0-9]+)\:\/\/([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(\/($|.+)?)*$/'; + if ( preg_match ( $pattern, $value ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::INTEGER: + if ( preg_match ( '/^[0-9]+$/', $value ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::FLOAT: + if ( preg_match ( '/^[0-9]+(\.[0-9]+)?$/', $value ) ) + return $value; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::TIMESTAMP: + if ( preg_match ( '/^[0-9]{10}$/', $value ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::DATE: + if (FALSE!==($time=strtotime($value))) + return $time; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + } // switch $type + throw new OC_Shorty_Exception ( "unknown request argument type '%s'", array($type) ); + } // function is_valid + + /** + * @method OC_Shorty_Type::normalize + * @brief cleanup and formal normalization of a given value according to its type + * Normalizes a given value according to its claimed type. + * This typically means trimming of string values, but sometimes also more specific actions. + * @param value the value to be normalized + * @param type the supposed type of the value + * @param strict boolean flag indicating if the normalization should be done in a strict way + * @returns the normalized value + * @throws error indicating a parameter violation + * @access public + * @author Christian Reiner + */ + static function normalize ( $value, $type, $strict=FALSE ) + { + if (NULL===(self::validate($value,$type,$strict))) + { + if ( ! $strict) + return NULL; + else + throw new OC_Shorty_Exception ( "invalid value '%1\$s' for type '%2\$s'", array($value,$type) ); + } // if + switch ( $type ) + { + case self::ID: return trim ( $value ); + case self::STATUS: return trim ( $value ); + case self::SORTKEY: return trim ( $value ); + case self::SORTVAL: return trim ( $value ); + case self::STRING: return trim ( $value ); + case self::URL: return trim ( $value ); + case self::INTEGER: return sprintf ( '%d', $value ); + case self::FLOAT: return sprintf ( '%f', $value ); + case self::TIMESTAMP: return trim ( $value ); + case self::DATE: return date ( 'Y-m-d', self::validate($value,OC_Shorty_Type::DATE) ); + } // switch $type + throw new OC_Shorty_Exception ( "unknown request argument type '%s'", array($type) ); + } // function normalize + + /** + * @method OC_Shorty_Type::req_argument + * @brief returns checked request argument or throws an error + * @param arg (string) name of the request argument to get_argument + * @param strict (bool) controls if an exception will be thrown upon a missing argument + * @returns (string) checked and prepared value of request argument + * @throws error indicating a parameter violation + * @access public + * @author Christian Reiner + */ + static function req_argument ( $arg, $type, $strict=FALSE ) + { + switch ( $_SERVER['REQUEST_METHOD'] ) + { + case 'POST': + if ( isset($_POST[$arg]) && !empty($_POST[$arg]) ) + return self::normalize ( urldecode($_POST[$arg]), $type ) ; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "missing mandatory argument '%1s'", array($arg) ); + case 'GET': + if ( isset($_GET[$arg]) && !empty($_GET[$arg]) ) + return self::normalize ( urldecode(trim($_GET[$arg])), $type, $strict ); + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "missing mandatory argument '%1s'", array($arg) ); + default: + throw new OC_Shorty_Exception ( "unexpected http request method '%1s'", array($_SERVER['REQUEST_METHOD']) ); + } + } // function req_argument + +} // class OC_Shorty_Query +?> diff --git a/apps/shorty/preferences.php b/apps/shorty/preferences.php new file mode 100644 index 00000000000..6e122fe410b --- /dev/null +++ b/apps/shorty/preferences.php @@ -0,0 +1,68 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file settings.php + * This plugins user preferences dialog + * The dialog will be included in the general framework of the user preferences page + * @access public + * @author Christian Reiner + */ + +OCP\Util::addStyle ( '3rdparty', 'chosen/chosen' ); +OCP\Util::addStyle ( 'shorty', 'shorty' ); +OCP\Util::addStyle ( 'shorty', 'preferences' ); + +OCP\Util::addScript ( '3rdparty', 'chosen/chosen.jquery.min' ); +OCP\Util::addScript ( 'shorty', 'shorty' ); +OCP\Util::addScript ( 'shorty', 'preferences' ); +if ( OC_Log::DEBUG==OC_Config::getValue( "loglevel", OC_Log::WARN ) ) + OCP\Util::addScript ( 'shorty', 'debug' ); + + +// fetch template +$tmpl = new OCP\Template ( 'shorty', 'tmpl_preferences' ); +// inflate template +$backend_types = OC_Shorty_Type::$BACKENDS; +// kick out static option again if no global backend base has been specified in the system settings +$backend_static_base = OCP\Config::getAppValue('shorty','backend-static-base',''); +if ( empty($backend_static_base) + || !parse_url($backend_static_base,PHP_URL_SCHEME) + || !parse_url($backend_static_base,PHP_URL_HOST) ) + unset($backend_types['static']); +// feed template engine +$tmpl->assign ( 'backend-types', $backend_types ); +$tmpl->assign ( 'backend-static-base', $backend_static_base ); +$tmpl->assign ( 'backend-bitly-user', OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-bitly-user','') ); +$tmpl->assign ( 'backend-bitly-key', OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-bitly-key','') ); +$tmpl->assign ( 'backend-google-key', OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-google-key','') ); +$tmpl->assign ( 'backend-tinycc-user', OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-tinycc-user','') ); +$tmpl->assign ( 'backend-tinycc-key', OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-tinycc-key','') ); +$tmpl->assign ( 'backend-type', OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-type','') ); +$tmpl->assign ( 'sms-control', OCP\Config::getUserValue(OCP\User::getUser(),'shorty','sms-control','disabled') ); +// render template +return $tmpl->fetchPage ( ); +?> diff --git a/apps/shorty/qrcode.php b/apps/shorty/qrcode.php new file mode 100644 index 00000000000..43b91b22afb --- /dev/null +++ b/apps/shorty/qrcode.php @@ -0,0 +1,100 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file qrcode.php + * Generates qr code barcodes cading a specified url + * @access public + * @author Christian Reiner + */ + +require_once ( '3rdparty/php/phpqrcode.php' ); + +$source = NULL; +// we try to guess what the request indicates: +// - a (source) url to be looked up in the database +foreach ($_GET as $key=>$val) // in case there are unexpected, additional arguments like a timestamp added by some stupid proxy +{ + switch ($key) + { + default: + // unrecognized key, we ignore it + break; + case 'url': + case 'uri': + case 'ref': + case 'source': + case 'target': + // a recognized argument key indicating an id to be looked up + $source = OC_Shorty_Type::req_argument($key,OC_Shorty_Type::URL,FALSE); + break 2; // skip switch AND foreach + } // switch +} // foreach + +// generate qr code for the specified url, IF it exists and is usable in the database +try +{ + if ( $source ) + { + $param = array ( 'source' => OC_Shorty_Type::normalize($source,OC_Shorty_Type::URL) ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_SOURCE ); + $result = $query->execute($param)->FetchAll(); + + if ( FALSE===$result ) + throw new OC_Shorty_HttpException ( 500 ); + elseif ( ! is_array($result) ) + throw new OC_Shorty_HttpException ( 500 ); + elseif ( 0==sizeof($result) ) + { + // no entry found => 404: Not Found + throw new OC_Shorty_HttpException ( 404 ); + } + elseif ( 1<sizeof($result) ) + { + // multiple matches => 409: Conflict + throw new OC_Shorty_HttpException ( 409 ); + } + elseif ( (!array_key_exists(0,$result)) || (!is_array($result[0])) || (!array_key_exists('source',$result[0])) ) + { + // invalid entry => 500: Internal Server Error + throw new OC_Shorty_HttpException ( 500 ); + } + elseif ( (!array_key_exists('source',$result[0])) || ('1'==$result[0]['expired']) ) + { + // entry expired => 410: Gone + throw new OC_Shorty_HttpException ( 410 ); + } + // generate qrcode, regardless of who sends the request + QRcode::png ( $source ); + } // if $source + else + { + // refuse forwarding => 403: Forbidden + throw new OC_Shorty_HttpException ( 403 ); + } +} catch ( OC_Shorty_Exception $e ) { header($e->getMessage()); } + +?> diff --git a/apps/shorty/relay.php b/apps/shorty/relay.php new file mode 100644 index 00000000000..077a3625afb --- /dev/null +++ b/apps/shorty/relay.php @@ -0,0 +1,140 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file relay.php + * This is the plugins central relaying feature + * All relay requests are handled by this file. + * @access public + * @author Christian Reiner + */ + +OCP\App::setActiveNavigationEntry ( 'shorty_index' ); + +$arg = NULL; +// we try to guess what the request indicates: +// - a (shorty) id to be looked up in the database resulting in a forwarding to the stored target +// - a (target) url to be added as a new shorty +// - none of the two, so just a plain list of existing shortys +foreach ($_GET as $key=>$val) // in case there are unexpected, additional arguments like a timestamp added by some stupid proxy +{ + switch ($key) + { + default: + // unrecognized key, we ignore it + break; + case 'id': + case 'shorty': + case 'ref': + case 'entry': + // a recognized argument key indicating an id to be looked up + $arg = OC_Shorty_Type::req_argument($key,OC_Shorty_Type::ID,FALSE); + break 2; // skip switch AND foreach + } // switch +} // foreach + +// an id was specified, ordinary or special meaning ? +if ( '0000000000'==$arg ) +{ + // this is a pseudo id, used to test the setup, so just return a positive message. + // this is used to test the setup of the static backend, shorty calls itself from there + OCP\Util::writeLog( 'shorty', "Positiv validation of static backend base url", OC_Log::INFO ); + OCP\JSON::success ( array ( ) ); + exit(); +} + +// now construct the target url and relay to it (if applicable) +try +{ + // detect requested shorty id from request + $p_id = trim ( OC_Shorty_Type::normalize($arg,OC_Shorty_Type::ID) ) ; + if ( $p_id ) + { + $param = array + ( + 'id' => $p_id, + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_FORWARD ); + $result = $query->execute($param)->FetchAll(); + if ( FALSE===$result ) + throw new OC_Shorty_HttpException ( 500 ); + elseif ( ! is_array($result) ) + throw new OC_Shorty_HttpException ( 500 ); + elseif ( 0==sizeof($result) ) + { + // no entry found => 404: Not Found + throw new OC_Shorty_HttpException ( 404 ); + } + elseif ( 1<sizeof($result) ) + { + // multiple matches => 409: Conflict + throw new OC_Shorty_HttpException ( 409 ); + } + elseif ( (!array_key_exists(0,$result)) || (!is_array($result[0])) || (!array_key_exists('target',$result[0])) ) + { + // invalid entry => 500: Internal Server Error + throw new OC_Shorty_HttpException ( 500 ); + } + elseif ( (!array_key_exists('target',$result[0])) || ('1'==$result[0]['expired']) ) + { + // entry expired => 410: Gone + throw new OC_Shorty_HttpException ( 410 ); + } + // an usable target ! + $target = trim($result[0]['target']); + // check status of matched entry + switch (trim($result[0]['status'])) + { + default: + case 'blocked': + // refuse forwarding => 403: Forbidden + throw new OC_Shorty_HttpException ( 403 ); + case 'private': + // check if user owns the Shorty, deny access if not + if ( $result[0]['user']!=OCP\User::getUser() ) + // refuse forwarding => 403: Forbidden + throw new OC_Shorty_HttpException ( 403 ); + // NO break; but fall through to the action in 'case public:' + case 'shared': + // check if we are a user, deny access if not + if ( ! OCP\User::isLoggedIn() ) + // refuse forwarding => 403: Forbidden + throw new OC_Shorty_HttpException ( 403 ); + // NO break; but fall through to the action in 'case public:' + case 'public': + // forward to target, regardless of who sends the request + header("HTTP/1.0 301 Moved Permanently"); + // http forwarding header + header ( sprintf('Location: %s', $target) ); + } // switch status + // register click in shorty + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_CLICK ); + $query->execute ( $param ); + exit(); + } // if id +} catch ( OC_Shorty_Exception $e ) { header($e->getMessage()); } + +?> diff --git a/apps/shorty/settings.php b/apps/shorty/settings.php new file mode 100644 index 00000000000..f10e354a7be --- /dev/null +++ b/apps/shorty/settings.php @@ -0,0 +1,52 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file settings.php + * This plugins system settings dialog + * The dialog will be included in the general framework of the system settings page + * @access public + * @author Christian Reiner + */ + +OCP\Util::addStyle ( '3rdparty', 'chosen/chosen' ); +OCP\Util::addStyle ( 'shorty', 'shorty' ); +OCP\Util::addStyle ( 'shorty', 'settings' ); + +OCP\Util::addScript ( '3rdparty', 'chosen/chosen.jquery.min' ); +OCP\Util::addScript ( 'shorty', 'shorty' ); +OCP\Util::addScript ( 'shorty', 'settings' ); +if ( OC_Log::DEBUG==OC_Config::getValue( "loglevel", OC_Log::WARN ) ) + OCP\Util::addScript ( 'shorty', 'debug' ); + + +// fetch template +$tmpl = new OCP\Template ( 'shorty', 'tmpl_settings' ); +// inflate template +$tmpl->assign ( 'backend-static-base', OCP\Config::getAppValue('shorty','backend-static-base','') ); +// render template +return $tmpl->fetchPage ( ); +?> diff --git a/apps/shorty/templates/tmpl_dlg_qrcode.php b/apps/shorty/templates/tmpl_dlg_qrcode.php new file mode 100644 index 00000000000..15b0eb2c366 --- /dev/null +++ b/apps/shorty/templates/tmpl_dlg_qrcode.php @@ -0,0 +1,52 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_dlg_qrcode.php + * Dialog popup to visualize and offer an url as a QRCode (2D barcode) + * @access public + * @author Christian Reiner + */ +?> + +<!-- additional (hidden) popup dialogs for specific usage actions --> +<fieldset id="dialog-qrcode" style="display:none;" class="" style="align:center;"> + <input id="qrcode-url" type="hidden" value="<?php echo $_['qrcode-url']; ?>"> + <span id='qrcode-img'> + <?php echo $l->t("Click for qrcode url").":"; ?> + <br> + <img width="100%" class="shorty-status" border="1" alt="<?php echo $l->t("QRCode"); ?>" + src="<?php echo OCP\Util::imagePath('shorty','loading-disk.gif'); ?>" > + </span> + <span id='qrcode-val' style="display:none;"> + <?php echo $l->t("Click for qrcode image").":"; ?> + <br> + <span class="shorty-framed"><a title="<?php echo $l->t("QRCode url").":"; ?>"></a></span> + </span> +</fieldset> +<!-- end of qrcode dialog --> diff --git a/apps/shorty/templates/tmpl_dlg_verify.php b/apps/shorty/templates/tmpl_dlg_verify.php new file mode 100644 index 00000000000..14b10d84174 --- /dev/null +++ b/apps/shorty/templates/tmpl_dlg_verify.php @@ -0,0 +1,70 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_dlg_verify.php + * Dialog popup to validate a configured static backend base + * @access public + * @author Christian Reiner + */ +?> + +<!-- a (usually hidden) dialog used for verification of the correct setup of the 'static' backend --> +<div id="dialog-verification" style="display:none;" title="<?php echo $l->t("'Static' backend: base url verification"); ?>"> + <!-- verification-in-progress --> + <div id="hourglass"> + <img src="<?php echo OCP\Util::imagePath('shorty', 'loading-disk.gif'); ?>"> + </div> + <!-- success --> + <div id="success" style="display:none;"> + <fieldset> + <legend> + <img class="shorty-status" src="<?php echo OCP\Util::imagePath('shorty','status/good.png'); ?>" alt="<?php $l->t('Success') ?>" title="<?php $l->t('Verification successful') ?>"> + <span id="title" class="title"><strong>Verification successful !</strong></span> + </legend> + <?php echo $l->t("<p>Great, your setup appears to be working fine ! </p>". + "<p>Requests to the configured base url '%s' are mapped to this ownClouds shorty module at '%1\$s'</p>". + "<p>Usage of that static backend is fine and safe as long as this setup is not altered.</p>", + array('<a id="verification-target" style="font-family:Monospace;"></a>',OCP\Util::linkToAbsolute('shorty','index.php')) );?> + </fieldset> + </div> + <!-- failure --> + <div id="failure" style="display:none;"> + <fieldset> + <legend> + <img class="shorty-status" src="<?php echo OCP\Util::imagePath('shorty','status/bad.png'); ?>" alt="<?php $l->t('Success') ?>" title="<?php $l->t('Verification successful') ?>"> + <span id="title" class="title"><strong>Verification failed !</strong></span> + </legend> + <?php echo $l->t("Sorry, but your setup appears not be be working correctly yet.<p>". + "Please check your setup and make sure that the configured base url '%1\$s' is indeed correct ". + "and that all requests to it are somehow mapped to ownClouds shorty module at '%2\$s'.", + array('<a id="verification-target" style="font-family:Monospace;"></a>',OCP\Util::linkToAbsolute('shorty','index.php')) );?> + </fieldset> + </div> +</div> +<!-- end of verification dialog --> diff --git a/apps/shorty/templates/tmpl_http_status.php b/apps/shorty/templates/tmpl_http_status.php new file mode 100644 index 00000000000..a43b4e3c328 --- /dev/null +++ b/apps/shorty/templates/tmpl_http_status.php @@ -0,0 +1,41 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_http_status.php + * Displays a human readable version of a classical http status error + * @access public + * @author Christian Reiner + */ +?> + +<ul> + <li class='error'> + <?php echo $_['explanation']; ?> + </li> +</ul> diff --git a/apps/shorty/templates/tmpl_index.php b/apps/shorty/templates/tmpl_index.php new file mode 100644 index 00000000000..fc4c4f91616 --- /dev/null +++ b/apps/shorty/templates/tmpl_index.php @@ -0,0 +1,66 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_index.php + * The general html environment where specific templates are bedded into. + * @access public + * @author Christian Reiner + */ +?> + +<!-- central notification area --> +<div id='notification'></div> + +<!-- top control bar --> +<div id="controls" class="controls shorty-controls" data-referrer="<?php if (array_key_exists('shorty-referrer',$_)) echo $_['shorty-referrer']; ?>"> + <!-- button to add a new entry to list --> + <input type="button" id="add" value="<?php echo OC_Shorty_L10n::t('New Shorty'); ?>"/> + <!-- display label: number of entries in list --> + <span> + <a class="shorty-prompt"><?php echo OC_Shorty_L10n::t('Number of entries') ?>:</a> + <a id="sum_shortys" class="shorty-value"> + <img src="<?php echo OCP\Util::imagePath('core', 'loading.gif'); ?>" /></a> + </span> + <!-- display label: total of clicks in list --> + <span> + <a class="shorty-prompt"><?php echo OC_Shorty_L10n::t('Total of clicks') ?>:</a> + <a id="sum_clicks" class="shorty-value"> + <img src="<?php echo OCP\Util::imagePath('core', 'loading.gif'); ?>" /></a> + </span> + <!-- the dialogs, hidden by default --> +<?php require_once('tmpl_url_add.php'); ?> +<?php require_once('tmpl_url_edit.php'); ?> +<?php require_once('tmpl_url_show.php'); ?> +<?php require_once('tmpl_url_share.php'); ?> +</div> + +<!-- the "desktop where the action takes place --> +<div id="desktop" class="right-content shorty-desktop"> +<?php require_once('tmpl_url_list.php'); ?> +</div> diff --git a/apps/shorty/templates/tmpl_preferences.php b/apps/shorty/templates/tmpl_preferences.php new file mode 100644 index 00000000000..61294c1914c --- /dev/null +++ b/apps/shorty/templates/tmpl_preferences.php @@ -0,0 +1,257 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_preferences.php + * Dialog to change user preferences, to be included in the clouds preferences page. + * @access public + * @author Christian Reiner + */ +?> + +<form id="shorty"> + <fieldset class="personalblock"> + <div id="title" class="title"> + <img class="" src="<?php echo OCP\Util::imagePath("shorty","shorty.png"); ?> "> + <strong>Shorty</strong> + </div> + <div id="settings"> + <!-- shortlet --> + <label for="shortlet" class="aspect"><?php echo $l->t("Shortlet").":";?></label> + <span id="shortlet"> + <a class="shortlet" + href="javascript:(function(){url=encodeURIComponent(location.href);window.open('<?php echo OCP\Util::linkToAbsolute('shorty', 'index.php'); ?>&url='+url, 'owncloud-shorty')%20})()"> + <?php echo $l->t("Add page as 'Shorty' to ownCloud"); ?> + </a> + </span> + <p> + <span class="explain"><em><?php echo $l->t("Drag this to your browser bookmarks."); + echo $l->t("Click it, for whatever site you want to create a Shorty."); ?></em></span> + </p> + <p> + <!-- backend selection --> + <label for="backend-type" class="aspect"><?php echo $l->t("Backend").":";?></label> + <!-- list of available backend types --> + <span style="margin-right:1em;"> + <select id="backend-type" name="backend-type" style="width:11em;" class="chosen" + placeholder="<?php echo $l->t("Choose service…"); ?>" > + <?php + foreach ( $_['backend-types'] as $value=>$display ) + echo sprintf ( " <option value=\"%s\" %s>%s</option>\n", + $value, + ($value==$_['backend-type']?'selected':''), + $l->t($display) ); + ?> + </select> + </span> + <!-- some additional fields: input, explanation and example --> + <!-- depending on the chosen backend-type above only one of the following span tags will be displayed --> + <span id="backend-none" class="backend-supplement" style="display:none;"> + <br/> + <label for="backend-example" class="aspect"> </label> + <span id="backend-example"> + <label for="example" class="aspect"><?php echo $l->t("Example").':';?></label> + <span id="example" class="example"><?php echo sprintf('http://%s%s<em><shorty id></em>',$_SERVER['SERVER_NAME'],OCP\Util::linkTo('shorty','',false)) ?></span> + </span> + <br/> + <span id="explain" class="explain"> + <?php echo sprintf('%s<br />%s<br />%s', + $l->t("No backend is used, direct links pointing to your ownCloud are generated."), + $l->t("Such links are most likely longer than those generated when using a backend."), + $l->t("However this option does not rely on any third party service and keeps your shortys under your control.") ); ?> + </span> + </span> + <!-- backend -static- --> + <span id="backend-static" class="backend-supplement" style="display:none;"> + <label for="backend-static-base" class="aspect"><?php echo $l->t("Base url").':';?></label> + <input id="backend-static-base" type="text" name="backend-static-base" + readonly disabled value="<?php echo $_['backend-static-base']; ?>" + placeholder="<?php echo $l->t("Specify a backend base url…"); ?>" style="width:25em;"> + <br/> + <label for="backend-example" class="aspect"> </label> + <span id="backend-example"> + <label for="example" class="aspect"><?php echo $l->t("Example").':';?></label> + <a id="example" class="example" title="<?php echo $l->t("Verification by click");?>"> + <?php echo sprintf('http://%s/<em><service></em>/<em><shorty id></em>',$_SERVER['SERVER_NAME']) ?> + </a> + </span> + <br/> + <span id="explain" class="explain"> + <?php echo sprintf("%s<br />\n%s<br />\n%s<br />\n%s", + $l->t("A static, rule-based backend is used, shorty links are generated relative to a given base url."), + $l->t("Since this setup depends on server based configuration rules the base url can only be specified in the 'Admin' section of the configuration."), + $l->t("Have a try with the example link provided, click it, it should result in a confirmation that your setup is working."), + $l->t("Only use this backend, if you can provide a short base url that is mapped the described way. Your shorties won't work otherwise.") ); ?> + </span> + </span> + <!-- backend bit.ly --> + <span id="backend-bitly" class="backend-supplement" style="display:none;"> + <label for="backend-bitly-user" class="aspect"><?php echo $l->t("bit.ly user").':';?></label> + <input id="backend-bitly-user" type="text" name="backend-bitly-user" value="<?php echo $_['backend-bitly-user']; ?>" + maxlength="256" placeholder="<?php echo $l->t("bit.ly user name");?>" style="width:10em;"> + <label for="backend-bitly-key" class="aspect"><?php echo $l->t("bit.ly key").':';?></label> + <input id="backend-bitly-key" type="text" name="backend-bitly-key" value="<?php echo $_['backend-bitly-key']; ?>" + maxlength="256" placeholder="<?php echo $l->t("bit.ly users key");?>" style="width:18em;"> + <br/> + <label for="backend-example" class="aspect"> </label> + <span id="backend-example"> + <label for="example" class="aspect"><?php echo $l->t("Example").':';?></label> + <span id="example" class="example"><?php echo sprintf('http://bitly.com/<em><shorty id></em>') ?></span> + </span> + <br/> + <span id="explain" class="explain"> + <?php echo sprintf("%s<br />\n%s<br />\n%s", + $l->t("The external 'bitly.com' service is used to register a short url for each generated shorty."), + $l->t("The service requires you to authenticate yourself by providing a valid bit.ly user name and an '%s'.", + sprintf('<a class="external" href="http://bitly.com/a/your_api_key" target="_blank">%s</a>',$l->t("API access key")) ), + $l->t("This means you have to '%s' at their site first.", + sprintf('<a class="external" href="http://bitly.com/a/sign_up" target="_blank">%s</a>',$l->t("register an account")) ) ); ?> + </span> + </span> + <!-- backend cligs --> + <span id="backend-cligs" class="backend-supplement" style="display:none;"> + <br/> + <label for="backend-example" class="aspect"> </label> + <span id="backend-example"> + <label for="example" class="aspect"><?php echo $l->t("Example").':';?></label> + <span id="example" class="example"><?php echo sprintf('http://cli.gs/<em><shorty id></em>') ?></span> + </span> + <br/> + <span id="explain" class="explain"> + <?php echo $l->t("The external 'cli.gs' service is used to register a short url for each generated shorty.");?> + </span> + </span> + <!-- backend is.gd --> + <span id="backend-isgd" class="backend-supplement" style="display:none;"> + <br/> + <label for="backend-example" class="aspect"> </label> + <span id="backend-example"> + <label for="example" class="aspect"><?php echo $l->t("Example").':';?></label> + <span id="example" class="example"><?php echo sprintf('http://is.gd/<em><shorty id></em>') ?></span> + </span> + <br/> + <span id="explain" class="explain"> + <?php echo $l->t("The external 'is.gd' service is used to register a short url for each generated shorty.");?> + </span> + </span> + <!-- backend google --> + <span id="backend-google" class="backend-supplement" style="display:none;"> + <label for="backend-google-key" class="aspect"><?php echo $l->t("API key").':';?></label> + <input id="backend-google-key" type="text" name="backend-google-key" value="<?php echo $_['backend-google-key']; ?>" + maxlength="256" placeholder="<?php echo $l->t("Google API key");?>" style="width:24em;"> + <br/> + <label for="backend-example" class="aspect"> </label> + <span id="backend-example"> + <label for="example" class="aspect"><?php echo $l->t("Example").':';?></label> + <span id="example" class="example"><?php echo sprintf('http://goo.gl/<em><shorty id></em>') ?></span> + </span> + <br/> + <span id="explain" class="explain"> + <?php echo sprintf("%s<br />\n%s<br />\n%s<br />\n%s", + $l->t("Googles external 'goo.gl service' is used to register a short url for each generated shorty."), + $l->t("You must provide a valid '%s' to use this service.", + sprintf('<a class="external" href="https://code.google.com/apis/console/" target="_blank">%s</a>',$l->t("Google API key")) ), + $l->t("This means you require a 'Google API console account'."), + $l->t("Register a new '%s' at their pages.", array( + sprintf('<a class="external" href="https://code.google.com/apis/console/" target="_blank">%s</a>',$l->t("Google API account")) ) ) );?> + </span> + </span> + <!-- backend tinycc --> + <span id="backend-tinycc" class="backend-supplement" style="display:none;"> + <label for="backend-tinycc-user" class="aspect"><?php echo $l->t("tiny.cc user").':'; ?></label> + <input id="backend-tinycc-user" type="text" name="backend-tinycc-user" value="<?php echo $_['backend-tinycc-user']; ?>" + maxlength="256" placeholder="<?php echo $l->t("tiny.cc user name"); ?>" style="width:10em;"> + <label for="backend-tinycc-key" class="aspect"><?php echo $l->t("tiny.cc key").':'; ?></label> + <input id="backend-tinycc-key" type="text" name="backend-tinycc-key" value="<?php echo $_['backend-tinycc-key']; ?>" + maxlength="256" placeholder="<?php echo $l->t("tiny.cc user key"); ?>" style="width:19em;"> + <br/> + <label for="backend-example" class="aspect"> </label> + <span id="backend-example"> + <label for="example" class="aspect"><?php echo $l->t("Example").':';?></label> + <span id="example" class="example"><?php echo sprintf('http://tiny.cc/<em><shorty id></em>') ?></span> + </span> + <br/> + <span id="explain" class="explain"> + <?php echo sprintf ( "%s<br />\n%s<br />\n%s", + $l->t("The external 'tiny.cc' service is used to register a short url for each generated shorty."), + $l->t("The service requires you to authenticate yourself by providing a valid tiny.cc user name and an api access key."), + $l->t("This means you have to register an '%s' at their site first.", array ( + sprintf('<a class="external" href="http://tiny.ccc/" target="_blank">%s</a>', $l->t("account") ) ) ) ); ?> + </span> + </span> + <!-- backend tinyURL --> + <span id="backend-tinyurl" class="backend-supplement" style="display:none;"> + <br/> + <label for="backend-example" class="aspect"> </label> + <span id="backend-example"> + <label for="example" class="aspect"><?php echo $l->t("Example").':'; ?></label> + <span id="example" class="example"><?php echo sprintf('http://ti.ny/<em><shorty id></em>') ?></span> + </span> + <br/> + <span id="explain" class="explain"> + <?php echo $l->t("The external 'ti.ny' service is used to register a short url for each generated shorty.");?> + </span> + </span> + <!-- backend turl --> + <span id="backend-turl" class="backend-supplement" style="display:none;"> + <br/> + <label for="backend-example" class="aspect"> </label> + <span id="backend-example"> + <label for="example" class="aspect"><?php echo $l->t("Example").':'; ?></label> + <span id="example" class="example"><?php echo sprintf('http://turl.ca/<em><shorty id></em>') ?></span> + </span> + <br/> + <span id="explain" class="explain"> + <?php echo $l->t("The external 'turl' service is used to register a short url for each generated shorty."); ?> + </span> + </span> + </p> + <p> + <!-- sms --> + <label for="sms" class="aspect"><?php echo $l->t("SMS").":";?></label> + <span id="sms" style="margin-right:1em;"> + <select id="sms-control" name="sms-control" style="width:11em;" class="chosen"> + <?php echo sprintf("<option value=\"disabled\" %s>%s</option>\n", + ('enabled'!=$_['sms-control']?'selected':''), + $l->t('disabled') ); ?> + <?php echo sprintf("<option value=\"enabled\" %s>%s</option>\n", + ('enabled'==$_['sms-control']?'selected':''), + $l->t('enabled')); ?> + </select> + <em><?php echo $l->t("Enabling the SMS option will offer sending a Shorty via SMS."); ?></em> + </span> + <p> + <span class="explain"><em><?php echo $l->t("Unfortunately support for 'SMS url handling' is usually only found on mobile devices like smart phones.")."<br>\n"; + echo $l->t("In addition, the implementations found in Android or iOS are minimalistic, buggy and differ from system to system.")."<br>\n"; + echo $l->t("In short: this might not work for you, therefore you can disable it…")."<br>\n";?></em></span> + </p> + </div> + <!-- a (usually hidden) dialog used for verification of the correct setup of the 'static' backend --> + <?php require_once('tmpl_dlg_verify.php'); ?> + </fieldset> +</form> diff --git a/apps/shorty/templates/tmpl_settings.php b/apps/shorty/templates/tmpl_settings.php new file mode 100644 index 00000000000..bcbab5ae014 --- /dev/null +++ b/apps/shorty/templates/tmpl_settings.php @@ -0,0 +1,70 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_settings.php + * Dialog to change plugin settings, to be included in the clouds settings page. + * @access public + * @author Christian Reiner + */ +?> + +<!-- settings of app 'shorty' --> +<form id="shorty"> + <fieldset class="personalblock"> + <legend> + <span id="title" class="title"> + <img class="" src="<?php echo OCP\Util::imagePath("shorty","shorty.png"); ?> "> + <strong>Shorty</strong> + </span> + </legend> + <div id="backend-static" class="backend-supplement"> + <label for="backend-static-base" class="aspect"><?php echo $l->t("Base url").':';?></label> + <input id="backend-static-base" type="text" name="backend-static-base" + value="<?php echo $_['backend-static-base']; ?>" + maxlength="256" placeholder="<?php echo $l->t('Specify a static base url…');?>" style="width:25em;"> + <br/> + <label for="backend-example" class="aspect"> </label> + <span id="backend-example"> + <label for="example" class="aspect"><?php echo $l->t("Example").':';?></label> + <a id="example" class="example" title="<?php echo $l->t("Verification by click");?>"> + <?php echo sprintf('http://%s/<em><service></em>/<em><shorty id></em>',$_SERVER['SERVER_NAME']) ?> + </a> + </span> + <br/> + <span id="explain" class="explain"><?php echo sprintf("%s<br />\n%s<br />\n%s<br />\n%s", + $l->t("Static, rule-based backend, generates shorty links relative to a given base url."), + $l->t("You have to take care that any request to the url configured here is internally mapped to the 'shorty' module."), + $l->t("Have a try with the example link provided, click it, it should result in a confirmation that your setup is working."), + $l->t("Leave empty if you can't provide a short base url that is mapped the described way.") ); ?> + </span> + </div> + + <?php require_once('tmpl_dlg_verify.php'); ?> + </fieldset> +</form> diff --git a/apps/shorty/templates/tmpl_url_add.php b/apps/shorty/templates/tmpl_url_add.php new file mode 100644 index 00000000000..abf51bdab73 --- /dev/null +++ b/apps/shorty/templates/tmpl_url_add.php @@ -0,0 +1,86 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_url_add.php + * A dialog to add a remote target url as a new shorty. + * @access public + * @author Christian Reiner + */ +?> + +<!-- (hidden) dialog to add a new shorty --> +<form id="dialog-add" class="shorty-dialog shorty-standalone"> + <fieldset> + <legend class=""> + <a id="close" class="shorty-close-button" + title="<?php echo OC_Shorty_L10n::t('Close'); ?>"> + <img alt="<?php echo OC_Shorty_L10n::t('Close'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/shade.png'); ?>"> + </a> + <?php echo OC_Shorty_L10n::t('Add a new shorty').':'; ?> + </legend> + <label for="target"><?php echo OC_Shorty_L10n::t('Target url').':'; ?></label> + <input id="target" name="target" type="text" maxlength="4096" data="" class=""/> + <br /> + <label for="meta"> <img id="busy" height="12px" src="<?php echo OCP\Util::imagePath('shorty', 'loading-led.gif'); ?>"></label> + <span id="meta" class="shorty-meta"> + <img id="staticon" class="shorty-icon" src="" width="16" data="<?php echo OCP\Util::imagePath('shorty', 'status/neutral.png'); ?>"> + <img id="schemicon" class="shorty-icon" src="" width="16" data="<?php echo OCP\Util::imagePath('shorty', 'blank.png'); ?>"> + <img id="favicon" class="shorty-icon" src="" width="16" data="<?php echo OCP\Util::imagePath('shorty', 'blank.png'); ?>"> + <img id="mimicon" class="shorty-icon" src="" width="16" data="<?php echo OCP\Util::imagePath('shorty', 'blank.png'); ?>"> + <a id="explanation" maxlength="80" data="" class="shorty-value"></a> + </span> + <br /> + <label for="title"><?php echo OC_Shorty_L10n::t('Shorty title').':'; ?></label> + <input id="title" name="title" type="text" maxlength="80" data="" class="" placeholder=""/> + <br /> + <label for="status"><?php echo OC_Shorty_L10n::t('Status').':'; ?></label> + <select id="status" name="status" data="shared" value="shared" class=""> + <?php + foreach ( OC_Shorty_Type::$STATUS as $status ) + if ( 'deleted'!=$status ) + echo sprintf ( "<option value=\"%s\">%s</option>\n", $status, OC_Shorty_L10n::t($status) ); + ?> + </select> + <span style="display:inline-block;"> + <label for="until"><?php echo OC_Shorty_L10n::t('Expiration').':'; ?></label> + <input id="until" name="until" type="text" maxlength="10" value="" + data="" class="" style="width:8em;" + placeholder="-<?php echo OC_Shorty_L10n::t('never'); ?>-" + icon="<?php echo OCP\Util::imagePath('shorty', 'calendar.png'); ?>"/> + </span> + <br /> + <label for="notes"><?php echo OC_Shorty_L10n::t('Notes').':'; ?></label> + <textarea id="notes" name="notes" maxlength="4096" data="" class="" + placeholder="<?php echo OC_Shorty_L10n::t('Anything that appears helpful …'); ?>"></textarea> + <br /> + <label for="confirm"></label> + <button id="confirm" class="shorty-button-submit"><?php echo OC_Shorty_L10n::t('Add as new'); ?></button> + </fieldset> +</form> diff --git a/apps/shorty/templates/tmpl_url_edit.php b/apps/shorty/templates/tmpl_url_edit.php new file mode 100644 index 00000000000..395b75ecab5 --- /dev/null +++ b/apps/shorty/templates/tmpl_url_edit.php @@ -0,0 +1,100 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_url_edit.php + * A dialog to modify some aspects of a selected shorty. + * @access public + * @author Christian Reiner + */ +?> + +<!-- (hidden) dialog to modify a stored shorty --> +<form id="dialog-edit" class="shorty-dialog shorty-standalone"> + <fieldset> + <legend class=""> + <a id="close" class="shorty-close-button" + title="<?php echo OC_Shorty_L10n::t('Close'); ?>"> + <img alt="<?php echo OC_Shorty_L10n::t('Close'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/shade.png'); ?>"> + </a> + <?php echo OC_Shorty_L10n::t('Modify shorty').':'; ?> + </legend> + <input id="id" name="id" type="hidden" readonly data="" class="" readonly disabled /> + <label for="source"><?php echo OC_Shorty_L10n::t('Source url').':'; ?></label> + <input id="source" name="source" type="text" data="" class="" readonly disabled /> + <br /> + <label for="target"><?php echo OC_Shorty_L10n::t('Target url').':'; ?></label> + <input id="target" name="target" type="text" data="" class="" readonly /> + <br /> + <label for="meta"> </label> + <span id="meta"> + <img id="staticon" class="shorty-icon" src="" data="<?php echo OCP\Util::imagePath('shorty', 'status/neutral.png'); ?>"> + <img id="schemicon" class="shorty-icon" src="" data="<?php echo OCP\Util::imagePath('shorty', 'blank.png'); ?>"> + <img id="favicon" class="shorty-icon" src="" data="<?php echo OCP\Util::imagePath('shorty', 'blank.png'); ?>"> + <img id="mimicon" class="shorty-icon" src="" data="<?php echo OCP\Util::imagePath('shorty', 'blank.png'); ?>"> + <a id="explanation" maxlength="80" data="" class="shorty-value"></a> + </span> + <br /> + <label for="title"><?php echo OC_Shorty_L10n::t('Shorty title').':'; ?></label> + <input id="title" name="title" type="text" maxlength="80" data="" class="" /> + <br /> + <label for="status"><?php echo OC_Shorty_L10n::t('Status').':'; ?></label> + <select id="status" name="status" data="shared" value="shared" style="width:8em;" class=""> + <?php + foreach ( OC_Shorty_Type::$STATUS as $status ) + if ( 'deleted'!=$status ) + echo sprintf ( "<option value=\"%s\">%s</option>\n", $status, OC_Shorty_L10n::t($status) ); + ?> + </select> + <span style="display:inline;"> + <label for="until"><?php echo OC_Shorty_L10n::t('Expiration').':'; ?></label> + <input id="until" name="until" type="text" value="" + maxlength="10" data="" class="" style="width:8em;" + placeholder="-<?php echo OC_Shorty_L10n::t('never'); ?>-" + icon="<?php echo OCP\Util::imagePath('shorty', 'calendar.png'); ?>" /> + </span> + <br /> + <label for="notes"><?php echo OC_Shorty_L10n::t('Notes').':'; ?></label> + <textarea id="notes" name="notes" maxlength="4096" data="" class="" + placeholder="<?php echo OC_Shorty_L10n::t('Anything that appears helpful …'); ?>"> + </textarea> + <br /> + <span class="label-line"> + <label for="clicks"><?php echo OC_Shorty_L10n::t('Clicks').':'; ?></label> + <input id="clicks" name="clicks" data="" type="textarea" class="" style="width:1em;" readonly disabled /> + <label for="created"><?php echo OC_Shorty_L10n::t('Creation').':'; ?></label> + <input id="created" name="created" type="text" data="" class="" style="width:7em;" readonly disabled /> + <label for="accessed"><?php echo OC_Shorty_L10n::t('Access').':'; ?></label> + <input id="accessed" name="accessed" type="text" data="" class="" style="width:10em;" readonly disabled /> + </span> + <br /> + <label for="confirm"></label> + <button id="confirm" class="shorty-button-submit"><?php echo OC_Shorty_L10n::t('Save'); ?></button> + </fieldset> +</form> diff --git a/apps/shorty/templates/tmpl_url_list.php b/apps/shorty/templates/tmpl_url_list.php new file mode 100644 index 00000000000..7a93eab9d8d --- /dev/null +++ b/apps/shorty/templates/tmpl_url_list.php @@ -0,0 +1,167 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_url_list.php + * A table to visualize the list of existing shortys. + * @access public + * @author Christian Reiner + */ +?> + +<div id="hourglass" class="shorty-hourglass" style="left:10em;top:10em;"><img src="<?php echo OCP\Util::imagePath('shorty', 'loading-disk.gif'); ?>"></div> +<div id="vacuum" class="shorty-vacuum"><span class="shorty-label"><?php echo OC_Shorty_L10n::t('List currently empty.') ?></span></div> + +<!-- the list of urls --> +<table id="list" class="shorty-list" style="display:none;"> + <thead> + <tr id="titlebar"> + <!-- a button to open/close the toolbar below --> + <th id="favicon"><span><img id="tools" alt="toolbar" title="toggle toolbar" + src="<?php echo OCP\Util::imagePath('shorty','actions/plus.png'); ?>" + data-plus="<?php echo OCP\Util::imagePath('shorty','actions/plus.png'); ?>" + data-minus="<?php echo OCP\Util::imagePath('shorty','actions/minus.png'); ?>"></span></th> + <th id="title" ><span><?php echo OC_Shorty_L10n::t('Title') ?></span></th> + <th id="target" ><span><?php echo OC_Shorty_L10n::t('Target') ?></span></th> + <th id="clicks" ><span><?php echo OC_Shorty_L10n::t('Clicks') ?></span></th> + <th id="until" ><span><?php echo OC_Shorty_L10n::t('Expiration') ?></span></th> + <th id="status" ><span><?php echo OC_Shorty_L10n::t('Status') ?></span></th> + <th id="action" ><span> </span></th> + </tr> + <!-- toolbar opened/closed by the button above --> + <tr id="toolbar"> + <th id="favicon"> + <div style="display:none;"> + <a id="reload"><img alt="<?php echo $l->t('reload'); ?>" title="<?php echo $l->t('Reload list'); ?>" src="<?php echo OCP\Util::imagePath('shorty','actions/reload.png'); ?>"></a> + </div> + </th> + <th id="title"> + <div style="display:none;"> + <img id="sort-up" class="shorty-sorter" data-sort-code="ta" data-sort-type="string" data-sort-direction='asc' + alt="<?php echo $l->t('up'); ?>" title="<?php echo $l->t('Sort ascending'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/up.png'); ?>"> + <img id="sort-down" class="shorty-sorter" data-sort-code="td" data-sort-type="string" data-sort-direction='desc' + alt="<?php echo $l->t('down'); ?>" title="<?php echo $l->t('Sort descending'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/down.png'); ?>"> + <input id='filter' type="text" value=""> + </div> + </th> + <th id="target"> + <div style="display:none;"> + <img id="sort-up" class="shorty-sorter" data-sort-code="ua" data-sort-type="string" data-sort-direction='asc' + alt="<?php echo $l->t('up'); ?>" title="<?php echo $l->t('Sort ascending'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/up.png'); ?>"> + <img id="sort-down" class="shorty-sorter" data-sort-code="ud" data-sort-type="string" data-sort-direction='desc' + alt="<?php echo $l->t('down'); ?>" title="<?php echo $l->t('Sort descending'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/down.png'); ?>"> + <input id='filter' type="text" value=""> + </div> + </th> + <th id="clicks"> + <div style="display:none;"> + <img id="sort-up" class="shorty-sorter" data-sort-code="ha" data-sort-type="int" data-sort-direction='asc' + alt="<?php echo $l->t('up'); ?>" title="<?php echo $l->t('Sort ascending'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/up.png'); ?>"> + <img id="sort-down" class="shorty-sorter" data-sort-code="hd" data-sort-type="int" data-sort-direction='desc' + alt="<?php echo $l->t('down'); ?>" title="<?php echo $l->t('Sort descending'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/down.png'); ?>"> + </div> + </th> + <th id="until"> + <div style="display:none;"> + <img id="sort-up" class="shorty-sorter" data-sort-code="da" data-sort-type="date" data-sort-direction='asc' + alt="<?php echo $l->t('up'); ?>" title="<?php echo $l->t('Sort ascending'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/up.png'); ?>"> + <img id="sort-down" class="shorty-sorter" data-sort-code="dd" data-sort-type="date" data-sort-direction='desc' + alt="<?php echo $l->t('down'); ?>" title="<?php echo $l->t('Sort descending'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/down.png'); ?>"> + </div> + </th> + <!-- status filter, colspan 2 to prevent width enhancement of column --> + <th id="status" colspan=2> + <div style="display:none;"> + <span id="horst" class="shorty-select"> + <select id='filter' value="" data-placeholder=" "> + <?php foreach($_['shorty-status'] as $status=>$label) + echo sprintf("<option value=\"%s\">%s</option>\n",($status?$label:''),$label); + ?> + </select> + </span> + </div> + </th> + </tr> + <!-- the 'dummy' row, a blueprint --> + <tr id="" + data-id="" + data-status="" + data-source="" + data-relay="" + data-title="" + data-favicon="" + data-target="" + data-clicks="" + data-until="" + data-created="" + data-accessed="" + data-notes=""> + <td id="favicon"></td> + <td id="title" ></td> + <td id="target" ></td> + <td id="clicks" ></td> + <td id="until" ></td> + <td id="status" ></td> + <td id="actions"> + <span class="shorty-actions"> + <a id="show" title="<?php echo $l->t('show'); ?>" class=""> + <img class="shorty-icon" alt="<?php echo $l->t('show'); ?>" title="<?php echo $l->t('Show details'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/info.png'); ?>" /> + </a> + <a id="edit" title="<?php echo $l->t('edit'); ?>" class=""> + <img class="shorty-icon" alt="<?php echo $l->t('modify'); ?>" title="<?php echo $l->t('Modify shorty'); ?>" + src="<?php echo OCP\Util::imagePath('core','actions/rename.png'); ?>" /> + </a> + <a id="del" title="<?php echo $l->t('delete'); ?>" class=""> + <img class="shorty-icon" alt="<?php echo $l->t('delete'); ?>" title="<?php echo $l->t('Delete shorty'); ?>" + src="<?php echo OCP\Util::imagePath('core','actions/delete.png'); ?>" /> + </a> + <a id="share" title="<?php echo $l->t('share'); ?>" class=""> + <img class="shorty-icon" alt="<?php echo $l->t('share'); ?>" title="<?php echo $l->t('Test and use links'); ?>" + src="<?php echo OCP\Util::imagePath('core','actions/share.png'); ?>" /> + </a> + <a id="open" title="<?php echo $l->t('open'); ?>" class=""> + <img class="shorty-icon" alt="<?php echo $l->t('open'); ?>" title="<?php echo $l->t('Open target'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/open.png'); ?>" /> + </a> + </span> + </td> + </tr> + </thead> + <!-- the standard body for non-empty lists --> + <tbody> + </tbody> +</table> diff --git a/apps/shorty/templates/tmpl_url_share.php b/apps/shorty/templates/tmpl_url_share.php new file mode 100644 index 00000000000..b42396d6a05 --- /dev/null +++ b/apps/shorty/templates/tmpl_url_share.php @@ -0,0 +1,89 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_url_share.php + * A dialog offering control over an entries state and offers the source url + * @access public + * @author Christian Reiner + */ +?> + +<!-- (hidden) dialog to share a shorty from the list --> +<form id="dialog-share" class="shorty-dialog shorty-embedded"> + <fieldset> + <legend class=""> + <a id="close" class="shorty-close-button" + title="<?php echo OC_Shorty_L10n::t('Close'); ?>"> + <img alt="<?php echo OC_Shorty_L10n::t('Close'); ?>" + src="<?php echo OCP\Util::imagePath('apps/shorty','actions/shade.png'); ?>"> + </a> + <?php echo OC_Shorty_L10n::t('Test and use').':'; ?> + </legend> + <input id="id" name="id" type="hidden" readonly data="" class="" readonly disabled /> + <label for="status"><?php echo OC_Shorty_L10n::t('Status').':'; ?></label> + <select id="status" name="status" data="" class="" value=""> + <?php + foreach ( OC_Shorty_Type::$STATUS as $status ) + if ( 'deleted'!=$status ) + echo sprintf ( "<option value=\"%s\">%s</option>\n", $status, OC_Shorty_L10n::t($status) ); + ?> + </select> + <br /> + <label for="source"><?php echo OC_Shorty_L10n::t('Source url').':'; ?></label> + <a id="source" class="shorty-clickable" target="_blank" + title="<?php echo OC_Shorty_L10n::t('Open source url'); ?>" + href=""></a> + <br /> + <label for="relay"><?php echo OC_Shorty_L10n::t('Relay url').':'; ?></label> + <a id="relay" class="shorty-clickable" target="_blank" + title="<?php echo OC_Shorty_L10n::t('Open relay url'); ?>" + href=""></a> + <br /> + <label for="target"><?php echo OC_Shorty_L10n::t('Target url').':'; ?></label> + <a id="target" class="shorty-clickable" target="_blank" + title="<?php echo OC_Shorty_L10n::t('Open target url'); ?>" + href=""></a> + <br /> + <img id="usage-email" name="usage-email" class="shorty-usage" alt="email" + src="<?php echo OCP\Util::imagePath('apps/shorty','usage/64/email.png'); ?>" + title="<?php echo OC_Shorty_L10n::t("Send by email"); ?>" /> + <img id="usage-sms" type="image" name="usage-sms" alt="sms" + class="shorty-usage <?php echo $_['sms-control']; ?>" + src="<?php echo OCP\Util::imagePath('apps/shorty','usage/64/sms.png'); ?>" + title="<?php echo OC_Shorty_L10n::t("Send by SMS"); ?>" /> + <img id="usage-qrcode" type="image" name="usage-qrcode" class="shorty-usage" alt="qrcode" + src="<?php echo OCP\Util::imagePath('apps/shorty','usage/64/qrcode.png'); ?>" + title="<?php echo OC_Shorty_L10n::t("Show as QRCode"); ?>" /> + <img id="usage-clipboard" type="image" name="usage-clipboard" class="shorty-usage" alt="clipbaord" + src="<?php echo OCP\Util::imagePath('apps/shorty','usage/64/clipboard.png'); ?>" + title="<?php echo OC_Shorty_L10n::t("Copy to clipboard"); ?>" /> + </fieldset> +</form> + +<?php require_once('tmpl_dlg_qrcode.php'); ?> diff --git a/apps/shorty/templates/tmpl_url_show.php b/apps/shorty/templates/tmpl_url_show.php new file mode 100644 index 00000000000..462d8e8b9cb --- /dev/null +++ b/apps/shorty/templates/tmpl_url_show.php @@ -0,0 +1,85 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ +?> + +<?php +/** + * @file templates/tmpl_url_show.php + * A read-only dialog visualizing all aspects of a selected shorty. + * @access public + * @author Christian Reiner + */ +?> + +<!-- (hidden) dialog to show a shorty from the list --> +<form id="dialog-show" class="shorty-dialog shorty-standalone"> + <fieldset> + <legend class=""> + <a id="close" class="shorty-close-button" + title="<?php echo OC_Shorty_L10n::t('Close'); ?>"> + <img alt="<?php echo OC_Shorty_L10n::t('Close'); ?>" + src="<?php echo OCP\Util::imagePath('shorty','actions/shade.png'); ?>"> + </a> + <?php echo OC_Shorty_L10n::t('Show details').':'; ?> + </legend> + <label for="source"><?php echo OC_Shorty_L10n::t('Source url').':'; ?></label> + <input id="source" name="source" type="text" data="" class="" readonly disabled /> + <br /> + <label for="target"><?php echo OC_Shorty_L10n::t('Target url').':'; ?></label> + <input id="target" name="target" data="" class="" readonly disabled /> + <br /> + <label for="meta"> </label> + <span id="meta"> + <img id="staticon" class="shorty-icon" src="" data="<?php echo OCP\Util::imagePath('shorty', 'status/neutral.png'); ?>"> + <img id="schemicon" class="shorty-icon" src="" data="<?php echo OCP\Util::imagePath('shorty', 'blank.png'); ?>"> + <img id="favicon" class="shorty-icon" src="" data="<?php echo OCP\Util::imagePath('shorty', 'blank.png'); ?>"> + <img id="mimicon" class="shorty-icon" src="" data="<?php echo OCP\Util::imagePath('shorty', 'blank.png'); ?>"> + <a id="explanation" maxlength="80" data="" class="shorty-value"></a> + </span> + <br /> + <label for="title"><?php echo OC_Shorty_L10n::t('Shorty title').':'; ?></label> + <input id="title" name="title" type="text" data="" class="" readonly disabled /> + <br /> + <label for="status"><?php echo OC_Shorty_L10n::t('Status').':'; ?></label> + <input id="status" name="status" type="text" data="" class="" style="width:8em;" readonly disabled /> + <span class="label-line"> + <label for="until"><?php echo OC_Shorty_L10n::t('Expiration').':'; ?></label> + <input id="until" name="until" type="text" data="" class="" style="width:12em;" readonly disabled /> + </span> + <br /> + <label for="notes"><?php echo OC_Shorty_L10n::t('Notes').':'; ?></label> + <input id="notes" name="notes" data="" class="" readonly disabled /> + <br /> + <span class="label-line"> + <label for="clicks"><?php echo OC_Shorty_L10n::t('Clicks').':'; ?></label> + <input id="clicks" name="clicks" data="" type="textarea" class="" style="width:1em;" readonly disabled /> + <label for="created"><?php echo OC_Shorty_L10n::t('Creation').':'; ?></label> + <input id="created" name="created" type="text" data="" class="" style="width:7em;" readonly disabled /> + <label for="accessed"><?php echo OC_Shorty_L10n::t('Access').':'; ?></label> + <input id="accessed" name="accessed" type="text" data="" class="" style="width:10em;" readonly disabled /> + </span> + </fieldset> +</form> |