����JFIF�����%%��� }!1AQa"q2���#B��R��$3br� %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz������������������������������������������������������������������������� w!1AQaq"2�B���� #3R�br� $4�%�&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz��������������������������������������������������������������������������?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|��O�������h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@��o�E��/�?��ߵE_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ ?�z�����������goڢ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?��=[�Qg�����o����Q@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y�����[����TP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,���|-��v��(���� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�������;~��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@�������?�_�����j������ (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@��o�E��/�?��ߵE_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ ?�z�����������goڢ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?��=[�Qg�����o����Q@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y�����[����TP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,���|-��v��(���� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�������;~��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@�������?�_�����j������ (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@��o�E��/�?��ߵE_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ ?�z�����������goڢ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?��=[�Qg�����o����Q@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y�����[����TP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,��������ο�O�P��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@����(���g���Y������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���V��Y|����Y����UP��@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P����,�����,��u������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j���h�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� �@���o�E��?�?����ο�U_�P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ _�z�����������g_ڪ�?��(�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (��?�/�=[�Qe�����g����U@��P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������k�w���~���v��������� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (�� (���տ�_�����:��T�~�@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@������/���?��j�?�5o�%��?��� g����U@�����&O3�����a�;�^=�wH���D��/��*� �fX�I���,������k?g_���?�5o�%��?��� g����U@�F�����������*������?�o�}��Τ~g��ʀ�#V��Y������~ο�T�j��K/� ������������z��������#;�~���A�;��� w�F�����������*���տ��_�@�o��5����EU������������u�誠��W��[�����������O��?jW���@��տ���@�o��5����EM������������v�訠�#V��Y�������������V��Zv��~����vw�~���c�Q@���,��~���kgo���?�5o�%��/��� o����Q@��o�%�>�ߤ���߳����S������?��o�%�~�ߠ�d�߳����S����g�P��j��K?� _������������[� g�D����[�;�TP7���������'Ѿ���=��;/�P��j��K?� _������������[� g�D����[�;�TP���,��~���kgo���a������۔���B{���ea�`T�+ �n%Ц �����j��K?� _������������[� g�D����[�;�TP���,��~���kgo����?���%�/�~�����#����x��c�~�q�v�t`ȫ��_'h���������'�]�;{s� Pp=N= 5���%�����ڜs�����=���J��A@�����Kp�b��}��X�����4g v+:�Բ�+60�ʩ,� @�����������I �uO�����ToUv��bgUl�cP�T?�#V��Y������������j��K?� _����������!��X��]���������TK�|4��`� ��#��P\y��aa >NgL��j��K?� _������������[� g�D����[�;�TP���,��~���kgo���o�F�����$��ہ�� ��vݞr6��S�q''*02���[� g�D����[�;�TP���,��~���kgo���?�5o�%��/��� o����Q@�F�����������*(��տ���@�o��5����EE������������v�訠��������~1�o���}G�L�������5o�%��/��� o����Q@�F�����������*(��տ���@�o��5����EE5����%�˷���r�v����y�\~���)(?0���=[� i����>��gc��N=����5o�%��/��� o����Q@�F�����������*(��W��Z�l����m#���X�wn_�j`0C6윅����5o�%��/��� o����Q@��տ��y9���gbO�G�5@�n�>���#V��Y������~ο�T��V��Y����9�gc��s�T.�?Z_��[� e�D����Y�:��UP���,������k?g_����_�=_� n�~~�rI������w�,"~ԓ�!72���)( u��#V��Y������~ο�T�j��K/� ��������������K
�����Kr_���}�De>~��Z=��pjX�n[p(�"� �a,Ub�/�×�<����;��<�����K>��o���[�:����V���,��$��ϧ�*�����5O����տ��_�@�o��5����EU5��o�%����?�ꜜm�_�;>Gbs�S�����@��տ��_�@�o��5����EU ��տ��}�~�����v?�������-��o�l��~�ȥ�v����r��B1���@��տ���A�?����ggP��c�S�`@%�*����տ��_�@�o��5����EU������������u�誠7���� O���!c�|0��ёv��4�+�X�Vx�RX3��8����K>��o���[�:���u#�x��#V��Y������~ο�T�j��K/� ������������[� e�D����Y�:��UP���,������k?g_���O��[� g�D����[�:��T��=_� k����~��k����c�;����.8����c��z��Ͽ�/��zc�o����F?Z_��[� e�D����Y�:��UP���,������k?g_���C���,�v����v�o���H������(�z���w�/�����v ��T.G��Ϡ���տ��_�@�o��5����EU������������u�誠��W��[��'����%��o���:�Cڕ�R̀���j���������?�o���[�;������g0q�?��o�%�>o�_��>�gf����~4�������������u�誠�z���7�/��o���������_��[� e�D����Y�:��UP���,������k?g_���C���,�|�����o��;�Ԟ��9�l�z��ؠ3|��O�X�~���;~�q����Z�F�����������*���տ��_�@�o��5����EU!��տ��}�~����-��G��I�T�������������u�誠�#V��Y������~ο�T�j��K/� ����������#�=_� n|���KbB�gtdM��"�ڒA#n�63�6�m�P�����,���/���gS�u����#�9��5o�%��?��� g����U@��o�%�o�_�����u��'�������?��o��� ���3��?go���|m�ڇ���-S�O��x��>���^�����7����x�]_�>�qke>���m��4��7P�Yހ��
0byt3m1n1
0byt3m1n1
Path:
/
hermes
/
bosweb
/
web
/
sb_web
/
web
/
sb_web
/
web
/
b2374
/
brunopereira.com
/
tikiwiki
/
lib
/
wiki
/
[
Home
]
File: editlib.php
<?php // (c) Copyright 2002-2012 by authors of the Tiki Wiki CMS Groupware Project // // All Rights Reserved. See copyright.txt for details and a complete list of authors. // Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. // $Id: editlib.php 41977 2012-06-17 14:03:23Z changi67 $ /**** * Initially just a collection of the functions dotted around tiki-editpage.php for v4.0 * Started in the edit_fixup experimental branch - jonnybradley Aug 2009 * */ class EditLib { private $tracesOn = false; // Fields for translation related methods. public $sourcePageName = null; public $targetPageName = null; public $oldSourceVersion = null; public $newSourceVersion = null; // Fields for handling links to external wiki pages private $external_wikis = null; // general function make_sure_page_to_be_created_is_not_an_alias($page, $page_info) { global $_REQUEST, $semanticlib, $access, $wikilib, $tikilib; require_once 'lib/wiki/semanticlib.php'; $aliases = $semanticlib->getAliasContaining($page, true); if (!$page_info && count($aliases) > 0) { $error_title = tra("Cannot create aliased page"); $error_msg = tra("You attempted to create the following page:")." ". "<b>$page</b>.\n<p>\n"; $error_msg .= tra("That page is an alias for the following pages").": "; foreach ($aliases as $an_alias) { $error_msg .= '<a href="'.$wikilib->editpage_url($an_alias['fromPage'], false).'">'.$an_alias['fromPage'].'</a>, '; } $error_msg .= "\n<p>\n"; $error_msg .= tra("If you want to create the page, you must first edit each the pages above, and remove the alias link it may contain. This link should look something like this"); $error_msg .= ": <b>(alias($page))</b>"; require_once('lib/tikiaccesslib.php'); $access->display_error(page, $error_title, "", true, $error_msg); } } function user_needs_to_specify_language_of_page_to_be_created($page, $page_info, $new_page_inherited_attributes = null) { global $_REQUEST, $multilinguallib, $prefs, $tikilib; if (isset($_REQUEST['need_lang']) && $_REQUEST['need_lang'] == 'n') { return false; } if ($prefs['feature_multilingual'] == 'n') { return false; } if ($page_info && isset($page_info['lang']) && $page_info['lang'] != '') { return false; } if (isset($_REQUEST['lang']) && $_REQUEST['lang'] != '') { return false; } if ($new_page_inherited_attributes != null && isset($new_page_inherited_attributes['lang']) && $new_page_inherited_attributes['lang'] != '') { return false; } return true; } // translation functions function isTranslationMode() { return $this->isUpdateTranslationMode() || $this->isNewTranslationMode(); } function isNewTranslationMode() { global $prefs; if ($prefs['feature_multilingual'] != 'y') { return false; } if (isset( $_REQUEST['translationOf'] ) && ! empty( $_REQUEST['translationOf'] )) { return true; } if (isset( $_REQUEST['is_new_translation'] ) && $_REQUEST['is_new_translation'] == 'y') { return true; } return false; } function isUpdateTranslationMode() { return isset( $_REQUEST['source_page'] ) && isset( $_REQUEST['oldver'] ) && (!isset($_REQUEST['is_new_translation']) || $_REQUEST['is_new_translation'] == 'n') && isset( $_REQUEST['newver'] ); } function prepareTranslationData() { global $_REQUEST, $tikilib, $smarty; $this->setTranslationSourceAndTargetPageNames(); $this->setTranslationSourceAndTargetVersions(); } private function setTranslationSourceAndTargetPageNames() { global $_REQUEST, $smarty; if (!$this->isTranslationMode()) { return; } $this->targetPageName = null; if (isset($_REQUEST['target_page'])) { $this->targetPageName = $_REQUEST['target_page']; } elseif (isset($_REQUEST['page'])) { $this->targetPageName = $_REQUEST['page']; } $smarty->assign('target_page', $this->targetPageName); $this->sourcePageName = null; if (isset($_REQUEST['translationOf']) && $_REQUEST['translationOf']) { $this->sourcePageName = $_REQUEST['translationOf']; } elseif (isset($_REQUEST['source_page'])) { $this->sourcePageName = $_REQUEST['source_page']; } $smarty->assign('source_page', $this->sourcePageName); if ($this->isNewTranslationMode()) { $smarty->assign('translationIsNew', 'y'); } else { $smarty->assign('translationIsNew', 'n'); } } private function setTranslationSourceAndTargetVersions() { global $_REQUEST, $tikilib; if (isset($_REQUEST['oldver'])) { $this->oldSourceVersion = $_REQUEST['oldver']; } else { // Note: -1 means a "virtual" empty version. $this->oldsourceVersion = -1; } if (isset($_REQUEST['newver'])) { $this->newSourceVersion = $_REQUEST['newver']; } else { // Note: version number of 0 means the most recent version. $this->newSourceVersion = 0; } } function aTranslationWasSavedAs($complete_or_partial) { if (!$this->isTranslationMode() || !isset($_REQUEST['save'])) { return false; } // We are saving a translation. Is it partial or complete? if ($complete_or_partial == 'complete' && isset($_REQUEST['partial_save'])) { return false; } else if ($complete_or_partial == 'partial' && !isset($_REQUEST['partial_save'])) { return false; } return true; } /** * Convert rgb() color definiton to hex color definiton * * @param unknown_type $col * @return The hex representation */ function parseColor(&$col) { if (preg_match("/^rgb\( *(\d+) *, *(\d+) *, *(\d+) *\)$/", $col, $parts) ) { $hex = str_pad(dechex($parts[1]), 2, '0', STR_PAD_LEFT) . str_pad(dechex($parts[2]), 2, '0', STR_PAD_LEFT) . str_pad(dechex($parts[3]), 2, '0', STR_PAD_LEFT); $hex = '#' . TikiLib::strtoupper($hex); } else { $hex = $col; } return $hex; } /** * Utility for walk_and_parse to process links * * @param array $args the attributes of the link * @param array $text the link text * @param string $src output string * @param array $p ['stack'] = closing strings stack */ private function parseLinkTag(&$args, &$text, &$src, &$p) { $link = ''; $link_open = ''; $link_close = ''; /* * parse the link classes */ $cl_wiki = false; $cl_wiki_page = false; // Wiki page $cl_ext_page = false; // external Wiki page $cl_external = false; // external web page $ext_wiki_name = ''; if ( isset($args['class']) && isset($args['href']) ) { $matches = array(); preg_match_all('/([^ ]+)/', $args['class']['value'], $matches); $classes = $matches[0]; for ($i=0, $count_classes = count($classes); $i< $count_classes; $i++) { $cl = $classes[$i]; switch ($cl) { case 'wiki': $cl_wiki = true; break; case 'wiki_page': $cl_wiki_page = true; break; case 'ext_page': $cl_ext_page = true; break; case 'external': $cl_external = true; break; default: // if the preceding class was 'ext_page', then we have the name of the external Wiki if ($i > 0 && $classes[$i-1] == 'ext_page') { $ext_wiki_name = $cl; } } } } /* * extract the target and the anchor from the href */ if ( isset($args['href']) ) { $href = urldecode($args['href']['value']); $matches = explode('#', $href); if ( count($matches) == 2) { $target = $matches[0]; $anchor = '#' . $matches[1]; } else { $target = $href; $anchor = ''; } } else { $target = ''; $anchor = ''; } /* * treat invalid external Wikis as web links */ if ( $cl_ext_page ) { // retrieve the definitions from the database if ($this->external_wikis == null) { global $tikilib; $query = 'SELECT `name`, `extwiki` FROM `tiki_extwiki`'; $this->external_wikis = $tikilib->fetchMap($query); } // name must be set and defined if ( !$ext_wiki_name || !isset($this->external_wikis[$ext_wiki_name]) ) { $cl_ext_page = false; $cl_wiki_page = false; } }; /* * construct the links according to the defined classes */ if ( $cl_wiki_page ) { /* * link to wiki page -> (( )) */ $link_open = '(('; $link_close = '))'; // remove the html part of the target $target = preg_replace('/tiki\-index\.php\?page\=/', '', $target); // construct the link $link = $target; if ($anchor) { $link .= '|' . $anchor; } } else if ( $cl_ext_page ) { /* * link to external Wiki page ((:)) */ $link_open = '(('; $link_close = '))'; // remove the extwiki definition from the target $def = preg_replace('/\$page/', '', $this->external_wikis[$ext_wiki_name]); $def = preg_quote($def, '/'); $target = preg_replace('/^' . $def.'/', '', $target); // construct the link $link = $ext_wiki_name . ':' . $target; if ($anchor) { $link .= '|' . $anchor; } } else if ($cl_wiki && !$cl_external && !$target && strlen($anchor) > 0 && substr($anchor, 0, 1) == '#' ) { /* * inpage links [#] */ $link_open = '['; $link_close = ']'; // construct the link $link = $target = $anchor; $anchor = ''; } else if ($cl_wiki && !$cl_external) { /* * other tiki resources [] * -> articles, ... */ $link_open = '['; $link_close = ']'; // construct the link $link = $target; } else if (!$cl_wiki && !$cl_external && !$text && isset($args['id']) && isset($args['id']['value']) ) { /* * anchor */ $link_open = '{ANAME()}'; $link_close = '{ANAME}'; $link = $args['id']['value']; } else { /* * other links [] */ $link_open = '['; $link_close = ']'; /* * parse the rel attribute */ $box = ''; if ( isset($args['class']) && isset($args['rel']) ) { $matches = array(); preg_match_all('/([^ ]+)/', $args['rel']['value'], $matches); $rels = $matches[0]; for ($i=0, $count_rels = count($rels); $i< $count_rels; $i++) { $r = $rels[$i]; if (preg_match('/^box/', $r) ) { $box = $r; } } } // construct the link $link = $target; if ($anchor) { $link .= $anchor; } // the box must be appended to the text if ($box) { $text .= '|' . $box; } } // convert links /* * flush the constructed link */ if ($link_open && $link_close) { $p['wiki_lbr']++; // force wiki line break mode // does the link text match the target? if ($target == trim($text)) { $text = ''; // make sure walk_and_parse() does not append any text. } else { $link .= '|'; // the text will be appended by walk_and_parse() } // process the tag and update the output $this->processWikiTag('a', $src, $p, $link_open, $link_close, true); $src .= $link; } } /** * Utility for walk_and_parse to process p and div tags * * @param bool $isPar True if we process a <p>, false if a <div> * @param array $args the attributes of the tag * @param string $src output string * @param array $p ['stack'] = closing strings stack */ private function parseParDivTag($isPar, &$args, &$src, &$p) { global $prefs; if (isset($args['style']) || isset($args['align'])) { $tag_name = $isPar ? 'p' : 'div'; // key for the $p[stack] $type = $isPar ? 'type="p", ' : ''; // used for {DIV()} $style = array(); $this->parseStyleAttribute($args['style']['value'], $style); /* * convert 'align' to 'style' definitions */ if (isset($args['align'])) { $style['text-align'] = $args['align']['value']; } /* * process all the defined styles */ foreach (array_keys($style) as $format) { switch ($format) { case 'text-align': if ($style[$format] == 'left') { $src .= "{DIV(${type}align=\"left\")}"; $p['stack'][] = array('tag' => $tag_name, 'string' => '{DIV}'); } elseif ($style[$format] == 'center') { $markup = ($prefs['feature_use_three_colon_centertag'] == 'y') ? ':::' : '::'; $this->processWikiTag($tag_name, $src, $p, $markup, $markup, false); } elseif ($style[$format] == 'right') { $src .= "{DIV(${type}align=\"right\")}"; $p['stack'][] = array('tag' => $tag_name, 'string' => '{DIV}'); } elseif ($style[$format] == 'justify') { $src .= "{DIV(${type}align=\"justify\")}"; $p['stack'][] = array('tag' => $tag_name, 'string' => '{DIV}'); } break; } // switch format } // foreach style } } /** * Utility for walk_and_parse to process span arguments * * @param array $args the attributes of the span * @param string $src output string * @param array $p ['stack'] = closing strings stack */ private function parseSpanTag(&$args, &$src, &$p) { if (isset($args['style'])) { $style = array(); $this->parseStyleAttribute($args['style']['value'], $style); $this->processWikiTag('span', $src, $p, '', '', true); // prepare the stacks, later we will append /* * The colors need to be handeled separatly; two style definitions become * one single wiki markup. */ $fcol = ''; $bcol = ''; if (isset($style['color'])) { $fcol = $this->parseColor($style['color']); unset($style['color']); } if (isset($style['background-color'])) { // background: color-def have been converted to background-color $bcol = $this->parseColor($style['background-color']); unset($style['background-color']); } if ($fcol || $bcol) { $col = "~~"; $col .= ($fcol ? $fcol : ' '); $col .= ($bcol ? ','.$bcol : ''); $col .= ':'; $this->processWikiTag('span', $src, $p, $col, '~~', true, true); } /* * Process the remaining format definitions */ foreach (array_keys($style) as $format) { switch ($format) { case 'font-weight': if ($style[$format] == 'bold') { $this->processWikiTag('span', $src, $p, '__', '__', true, true); } break; case 'font-style': if ($style[$format] == 'italic') { $this->processWikiTag('span', $src, $p, '\'\'', '\'\'', true, true); } case 'text-decoration': if ($style[$format] == 'line-through') { $this->processWikiTag('span', $src, $p, '--', '--', true, true); } else if ($style[$format] == 'underline') { $this->processWikiTag('span', $src, $p, '===', '===', true, true); } } // switch format } // foreach style } // style } /** * Parse a html style definition into an array * * This method tries to expand the shorthand definitions, such as 'background:', * to the correspoinding key/value paris. If a definition is unknown, it is kept. * * @param string $style The value of the style attribute * @param array $parsed key/value pairs */ function parseStyleAttribute(&$style, &$parsed) { $matches = array(); preg_match_all('/ *([^ :]+) *: *([^;]+) *;?/', $style, $matches); for ($i=0, $count_matches = count($matches[0]); $i<$count_matches; $i++) { $key = $matches[1][$i]; $value = trim($matches[2][$i]); /* * shortand list 'background:' * - set 'background-color' */ if ($key == 'background') { $unprocessed = ''; $shorthand = array(); $this->parseStyleList($value, $shorthand); foreach ($shorthand as $s) { switch ($s) { case preg_match('/^#(\w{3,6})$/', $s) > 0: $parsed['background-color'] = $s; break; case preg_match('/^rgb\(.*\)$/', $s) > 0: $parsed['background-color'] = $s; break; default: $unprocessed .= ' ' . $s; } } // foreach shorthand // keep unprocessed list entries $value = trim($unprocessed); } // background: // save the result if ($value) { $parsed[$key] = $value; } } // style definitions } /** * Parse a space separated list of html styles * * Example: "rgb( 1, 2, 3) url(background.gif)" * * @param string $list List of styles * @param array $parsed The parsed list */ function parseStyleList(&$list, &$parsed) { $matches = array(); preg_match_all('/(?:[[:graph:]]+\([^\)]*\))|(?:[^ ]+)/', $list, $matches); $parsed = $matches[0]; } /** * Utility of walk_and_parse to process a wiki tag * * Wiki tags need a special treatment: In html, a tag may contain * several line breaks. In Wiki however, line breaks are often not allowed * and sometimes additional line breaks are required. * * This method saves Wiki tags an line break information in separate stacks. * These stackes are used in walk_and_parse to: * - Output the required markup before and after the linebreaks (<br />). * - To ensure that linebreaks are, if required, inserted at the correct place (\n). * * @param string $tag The name of the html tag * @param string $src Th Output string * @param array $p ['stack'] = closing strings stack, * @param string $begin The wiki markup that begins the tag * @param string $end The wiki markup that ends the tag * @param bool $is_inline True if the tag is inline, false if the tag must span exacly one line. * @param bool $append True = append to the topmost element on the stack, false = create a new element on the stack */ private function processWikiTag($tag, &$src, &$p, $begin, $end, $is_inline, $append = false) { // append=false, create new entries on the stack if (!$append) { $p['stack'][] = array('tag' => $tag, 'string' => '', 'wikitags' => 0 ); $p['wikistack'][] = array( 'begin' => array(), 'end' => array() ); }; // get the entry points on the stacks $key = end(array_keys($p['wikistack'])); $wiki = &$p['wikistack'][$key]; $key = end(array_keys($p['stack'])); $stack = &$p['stack'][$key]; $string = &$stack['string']; // append to the stacks $wiki['begin'][] = $begin; $wiki['end'][] = $end; $string = $end . $string; $stack['wikitags']++; // update the output string if (!$is_inline) { $this->startNewLine($src); } $src .= $begin; } function saveCompleteTranslation() { global $multilinguallib, $tikilib; $sourceInfo = $tikilib->get_page_info($this->sourcePageName); $targetInfo = $tikilib->get_page_info($this->targetPageName); $multilinguallib->propagateTranslationBits( 'wiki page', $sourceInfo['page_id'], $targetInfo['page_id'], $sourceInfo['version'], $targetInfo['version'] ); $multilinguallib->deleteTranslationInProgressFlags($targetInfo['page_id'], $sourceInfo['lang']); } function savePartialTranslation() { global $multilinguallib, $tikilib; $sourceInfo = $tikilib->get_page_info($this->sourcePageName); $targetInfo = $tikilib->get_page_info($this->targetPageName); $multilinguallib->addTranslationInProgressFlags($targetInfo['page_id'], $sourceInfo['lang']); } /** * Function to take html from ckeditor and parse back to wiki markup * Used by "switch editor" and when saving in wysiwyg_htmltowiki mode * When saving in mixed "html" mode the "unparsing" is done in JavaScript client-side * * @param $inData editor content * @return string wiki markup */ function parseToWiki( $inData ) { global $prefs; $parsed = $this->partialParseWysiwygToWiki($inData); // remove cke type plugin wrappers $parsed = html_entity_decode($parsed, ENT_QUOTES, 'UTF-8'); $parsed = preg_replace('/\t/', '', $parsed); // remove all tabs inserted by the CKE $parsed = preg_replace_callback('/<pre class=["\']tiki_plugin["\']>(.*?)<\/pre>/ims', array($this, 'parseToWikiPlugin'), $parsed); // rempve plugin wrappers $parsed = $this->parse_html($parsed); $parsed = preg_replace('/\{img\(? src=.*?img\/smiles\/icon_([\w\-]*?)\..*\}/im', '(:$1:)', $parsed); // "unfix" smilies $parsed = preg_replace('/ /m', ' ', $parsed); // spaces $parsed = preg_replace('/!(?:\d\.)+/', '!#', $parsed); // numbered headings if ($prefs['feature_use_three_colon_centertag'] == 'y') { // numbered and centerd headings $parsed = preg_replace('/!:::(?:\d\.)+ *(.*):::/', '!#:::\1:::', $parsed); } else { $parsed = preg_replace('/!::(?:\d\.)+ *(.*)::/', '!#::\1::', $parsed); } // remove empty center tags if ($prefs['feature_use_three_colon_centertag'] == 'y') { // numbered and centerd headings $parsed = preg_replace('/::: *:::\n/', '', $parsed); } else { $parsed = preg_replace('/:: *::\n/', '', $parsed); } // Put back htmlentities as normal char $parsed = htmlspecialchars_decode($parsed, ENT_QUOTES); return $parsed; } function parseToWikiPlugin($matches) { if (count($matches) > 1) { return nl2br($matches[1]); } } /** * Render html to send to ckeditor, including parsing plugins for wysiwyg editing * From both wiki page source (for wysiwyg_htmltowiki) and "html" modes * * @param $inData page data, can be wiki or mixed html/wiki * @param bool $fromWiki set if converting from wiki page using "switch editor" * @param bool $isHtml set if are doing WYSIWYG Wiki * @return string html to send to ckeditor */ function parseToWysiwyg( $inData, $fromWiki = false, $isHtml = false ) { global $tikilib, $tikiroot, $prefs; // Parsing page data for wysiwyg editor $inData = $this->partialParseWysiwygToWiki($inData); // remove any wysiwyg plugins so they don't get double parsed $parsed = preg_replace('/(!!*)[\+\-]/m', '$1', $inData); // remove show/hide headings $parsed = preg_replace('/'/', '\'', $parsed); // catch single quotes at html entities $parsed = $tikilib->parse_data( $parsed, array( 'absolute_links'=>true, 'noheaderinc'=>true, 'suppress_icons' => true, 'ck_editor' => true, 'is_html' => ($isHtml && !$fromWiki), 'process_wiki_paragraphs' => (!$isHtml || $fromWiki), 'process_double_brackets' => 'n' ) ); if ($fromWiki) { $parsed = preg_replace('/^\s*<p> [\s]*<\/p>\s*/iu', '', $parsed); // remove added empty <p> } $parsed = preg_replace('/<span class=\"img\">(.*?)<\/span>/im', '$1', $parsed); // remove spans round img's // Workaround Wysiwyg Image Plugin Editor in IE7 erases image on insert http://dev.tiki.org/item3615 $parsed2 = preg_replace('/(<span class=\"tiki_plugin\".*?plugin=\"img\".*?><\/span>)<\/p>/is', '$1<span> </span></p>', $parsed); if ($parsed2 !== null) { $parsed = $parsed2; } // Fix IE7 wysiwyg editor always adding absolute path $search = '/(<a[^>]+href=\")https?\:\/\/' . preg_quote($_SERVER['HTTP_HOST'].$tikiroot, '/') . '([^>]+_cke_saved_href)/i'; $parsed = preg_replace($search, '$1$2', $parsed); return $parsed; } /** * Converts wysiwyg plugins into wiki. * Also processes headings by removing surrounding <p> (possibly for wysiwyg_wiki_semi_parsed but not tested) * Also used by ajax preview in tiki-auto_save.php * * @param string $inData page data - mostly html but can have a bit of wiki in it * @return string html with wiki plugins */ function partialParseWysiwygToWiki( $inData ) { // de-protect ck_protected comments $ret = preg_replace('/<!--{cke_protected}{C}%3C!%2D%2D%20end%20tiki_plugin%20%2D%2D%3E-->/i', '<!-- end tiki_plugin -->', $inData); // remove the wysiwyg plugin elements leaving the syntax only remaining $ret = preg_replace('/<(?:div|span)[^>]*syntax="(.*)".*end tiki_plugin --><\/(?:div|span)>/Umis', "$1", $ret); // preg_replace blows up here with a PREG_BACKTRACK_LIMIT_ERROR on pages with "corrupted" plugins if (!$ret) { $ret = $inData; } // take away the <p> that f/ck introduces around wiki heading ! to have maketoc/edit section working $ret = preg_replace('/<p>!(.*)<\/p>/iu', "!$1\n", $ret); // strip totally empty <p> tags generated in ckeditor 3.4 $ret = preg_replace('/\s*<p>[\s]*<\/p>\s*/iu', "$1\n", $ret); return $ret; } // parse HTML functions /** * \brief Parsed HTML tree walker (used by HTML sucker) * * This is initial implementation (stupid... w/o any intellegence (almost :)) * It is rapidly designed version... just for test: 'can this feature be useful'. * Later it should be replaced by well designed one :) don't bash me now :) * * \param &$c array -- parsed HTML * \param &$src string -- output string * \param &$p array -- ['stack'] = closing strings stack, ['listack'] = stack of list types currently opened ['first_td'] = flag: 'is <tr> was just before this <td>' ['first_tr'] = flag: 'is <table> was just before this <tr>' */ function walk_and_parse(&$c, &$src, &$p, $head_url ) { global $prefs; // If no string if (!$c) { return; } for ($i=0; $i <= $c["contentpos"]; $i++) { // If content type 'text' output it to destination... if ($c[$i]["type"] == "text") { if ( ! ctype_space($c[$i]["data"]) ) { $add = $c[$i]["data"]; $add = str_replace(array("\r","\n"), '', $add); $add = str_replace(' ', ' ', $add); $src .= $add; } } elseif ($c[$i]["type"] == "comment") { $src .= preg_replace('/<!--/', "\n~hc~", preg_replace('/-->/', "~/hc~\n", $c[$i]["data"])); } elseif ($c[$i]["type"] == "tag") { if ($c[$i]["data"]["type"] == "open") { // Open tag type // deal with plugins - could be either span of div so process before the switch statement if (isset($c[$i]['pars']['plugin']) && isset($c[$i]['pars']['syntax'])) { // handling for tiki plugins $src .= html_entity_decode($c[$i]['pars']['syntax']['value']); $more_spans = 1; $elem_type = $c[$i]["data"]["name"]; $other_elements = 0; $j = $i + 1; while ($j < $c['contentpos']) { // loop through contents of this span and discard everything if ($c[$j]['data']['name'] == $elem_type && $c[$j]['data']['type'] == 'close') { $more_spans--; if ($more_spans === 0) { break; } // } else if ($c[$j]['data']['name'] == 'br' && $more_spans === 1 && $other_elements === 0) { } else if ($c[$j]['data']['name'] == $elem_type && $c[$j]['data']['type'] == 'open') { $more_spans++; } else if ($c[$j]['data']['type'] == 'open' && $c[$j]['data']['name'] != 'br' && $c[$j]['data']['name'] != 'img' && $c[$j]['data']['name'] != 'input') { $other_elements++; } else if ($c[$j]['data']['type'] == 'close') { $other_elements--; } $j++; } $i = $j; // skip everything that was inside this span } $isPar = false; // assuming "div" when calling parseParDivTag() switch ($c[$i]["data"]["name"]) { // Tags we don't want at all. case "meta": $c[$i]["content"] = ''; break; // others we do want case "br": if ($p['wiki_lbr']) { // "%%%" or "\n" ? $src .= ' %%% '; } else { // close all wiki tags foreach ( array_reverse($p['wikistack']) as $wiki_arr ) { foreach ( array_reverse($wiki_arr['end']) as $end ) { $src .= $end; } } $src .= "\n"; // for lists, we must prepend '+' to keep the indentation if ($p['listack']) { $src .= str_repeat('+', count($p['listack'])); } // reopen all wikitags foreach ( $p['wikistack'] as $wiki_arr ) { foreach ( $wiki_arr['begin'] as $begin) { $src .= $begin; } } } break; case "hr": $src .= $this->startNewLine($src) . '---'; break; case "title": $src .= "\n!"; $p['stack'][] = array('tag' => 'title', 'string' => "\n"); break; case "p": $isPar = true; if ($src && $prefs['feature_wiki_paragraph_formatting'] !== 'y') { $src.="\n"; } case "div": // Wiki parsing creates divs for center if (isset($c[$i]['pars'])) { $this->parseParDivTag($isPar, $c[$i]['pars'], $src, $p); } else { // normal para or div $src .= $this->startNewLine($src); $p['stack'][] = array('tag' => $c[$i]['data']['name'], 'string' => "\n\n"); } break; case "span": if ( isset($c[$i]['pars'])) { $this->parseSpanTag($c[$i]['pars'], $src, $p); } break; case "b": $this->processWikiTag('b', $src, $p, '__', '__', true); break; case "i": $this->processWikiTag('i', $src, $p, '\'\'', '\'\'', true); break; case "em": $this->processWikiTag('em', $src, $p, '\'\'', '\'\'', true); break; case "strong": $this->processWikiTag('strong', $src, $p, '__', '__', true); break; case "u": $this->processWikiTag('u', $src, $p, '===', '===', true); break; case "strike": $this->processWikiTag('strike', $src, $p, '--', '--', true); break; case "del": $this->processWikiTag('del', $src, $p, '--', '--', true); break; case "center": if ($prefs['feature_use_three_colon_centertag'] == 'y') { $src .= ':::'; $p['stack'][] = array('tag' => 'center', 'string' => ':::'); } else { $src .= '::'; $p['stack'][] = array('tag' => 'center', 'string' => '::'); } break; case "code": $src .= '-+'; $p['stack'][] = array('tag' => 'code', 'string' => '+-'); break; case "dd": $src .= ':'; $p['stack'][] = array('tag' => 'dd', 'string' => "\n"); break; case "dt": $src .= ';'; $p['stack'][] = array('tag' => 'dt', 'string' => ''); break; case "h1": case "h2": case "h3": case "h4": case "h5": case "h6": $p['wiki_lbr']++; // force wiki line break mode $hlevel = (int) $c[$i]["data"]["name"]{1}; if (isset($c[$i]['pars']['style']['value']) && strpos($c[$i]['pars']['style']['value'], 'text-align: center;') !== false ) { if ($prefs['feature_use_three_colon_centertag'] == 'y') { $src .= $this->startNewLine($src) . str_repeat('!', $hlevel) . ':::'; $p['stack'][] = array('tag' => $c[$i]['data']['name'], 'string' => ":::\n"); } else { $src .= $this->startNewLine($src) . str_repeat('!', $hlevel) . '::'; $p['stack'][] = array('tag' => $c[$i]['data']['name'], 'string' => "::\n"); } } else { // normal para or div $src .= $this->startNewLine($src) . str_repeat('!', $hlevel); $p['stack'][] = array('tag' => $c[$i]["data"]["name"], 'string' => "\n"); } break; case "pre": $src .= "~pre~\n"; $p['stack'][] = array('tag' => 'pre', 'string' => "~/pre~\n"); break; case "sub": $src .= "{SUB()}"; $p['stack'][] = array('tag' => 'sub', 'string' => "{SUB}"); break; case "sup": $src .= "{SUP()}"; $p['stack'][] = array('tag' => 'sup', 'string' => "{SUP}"); break; case "tt" : $src .= '{DIV(type="tt")}'; $p['stack'][] = array('tag' => 'tt', 'string' => "{DIV}"); break; case "s" : $src .= $this->processWikiTag('s', $src, $p, '--', '--', true); break; // Table parser case "table": $src .= $this->startNewLine($src) . '||'; $p['stack'][] = array('tag' => 'table', 'string' => '||'); $p['first_tr'] = true; break; case "tr": $src .= $p['first_tr'] ? '' : $this->startNewLine($src); $p['first_tr'] = false; $p['first_td'] = true; break; case "td": $src .= $p['first_td'] ? '' : '|'; $p['first_td'] = false; break; // Lists parser case "ul": $p['listack'][] = '*'; break; case "ol": $p['listack'][] = '#'; break; case "li": // Generate wiki list item according to current list depth. $src .= $this->startNewLine($src) . str_repeat(end($p['listack']), count($p['listack'])); break; case "font": // If color attribute present in <font> tag if (isset($c[$i]["pars"]["color"]["value"])) { $src .= '~~'.$c[$i]["pars"]["color"]["value"].':'; $p['stack'][] = array('tag' => 'font', 'string' => '~~'); } break; case "img": // If src attribute present in <img> tag if (isset($c[$i]["pars"]["src"]["value"])) // Note what it produce (img) not {img}! Will fix this below... if ( strstr($c[$i]["pars"]["src"]["value"], "http:") ) { $src .= '{img src="'.$c[$i]["pars"]["src"]["value"].'"}'; } else { $src .= '{img src="'.$head_url.$c[$i]["pars"]["src"]["value"].'"}'; } break; case "a": if (isset($c[$i]['pars'])) { // get the link text $text = ''; if ( $i < count($c) ) { $next_token = &$c[$i+1]; if (isset($next_token['type']) && $next_token['type'] == 'text' && isset($next_token['data']) ) { $text = &$next_token['data']; } } // parse the link $this->parseLinkTag($c[$i]['pars'], $text, $src, $p); } // deactivated by mauriz, will be replaced by the routine above // If href attribute present in <a> tag /* if (isset($c[$i]["pars"]["href"]["value"])) { if ( strstr( $c[$i]["pars"]["href"]["value"], "http:" )) { $src .= '['.$c[$i]["pars"]["href"]["value"].'|'; } else { $src .= '['.$head_url.$c[$i]["pars"]["href"]["value"].'|'; } $p['stack'][] = array('tag' => 'a', 'string' => ']'); } if ( isset($c[$i]["pars"]["name"]["value"])) { $src .= '{ANAME()}'.$c[$i]["pars"]["name"]["value"].'{ANAME}'; } */ break; } // end switch on tag name } else { // This is close tag type. Is that smth we r waiting for? switch ($c[$i]["data"]["name"]) { case "ul": if (end($p['listack']) == '*') array_pop($p['listack']); if ( empty($p['listack']) ) $src .= "\n"; break; case "ol": if (end($p['listack']) == '#') array_pop($p['listack']); if ( empty($p['listack']) ) $src .= "\n"; break; default: $e = end($p['stack']); if ($c[$i]["data"]["name"] == $e['tag']) { $src .= $e['string']; array_pop($p['stack']); } break; } // update the wiki stack if (isset($e['wikitags']) && $e['wikitags']) { for ( $i_wiki = 0; $i_wiki < $e['wikitags']; $i_wiki++ ) { array_pop($p['wikistack']); } } // can we leave wiki line break mode ? switch ($c[$i]["data"]["name"]) { case "a": case "h1": case "h2": case "h3": case "h4": case "h5": case "h6": $p['wiki_lbr']--; break; } } } // Recursive call on tags with content... if (isset($c[$i]["content"])) { if (substr($src, -1) != " ") $src .= " "; $this->walk_and_parse($c[$i]["content"], $src, $p, $head_url); } } if (substr($src, -2) == "\n\n") { // seem to always get too many line ends $src = substr($src, 0, -2); } } // end walk_and_parse function startNewLine(&$str) { if (strlen($str) && substr($str, -1) != "\n") { $str .= "\n"; } } /** * wrapper around zaufi's HTML sucker code just to use the html to wiki bit * * \param &$c string -- HTML in * \param &$src string -- output string */ function parse_html(&$inHtml) { global $smarty; include ('lib/htmlparser/htmlparser.inc'); // Read compiled (serialized) grammar $grammarfile = 'lib/htmlparser/htmlgrammar.cmp'; if (!$fp = @fopen($grammarfile, 'r')) { $smarty->assign('msg', tra("Can't parse HTML data - no grammar file")); $smarty->display("error.tpl"); die; } $grammar = unserialize(fread($fp, filesize($grammarfile))); fclose($fp); // process a few ckeditor artifacts $inHtml = str_replace('<p></p>', '', $inHtml); // empty p tags are invisible // create parser object, insert html code and parse it $htmlparser = new HtmlParser($inHtml, $grammar, '', 0); $htmlparser->Parse(); // Should I try to convert HTML to wiki? $out_data = ''; /* * ['stack'] = array * Speacial keys introduced to convert to Wiki * - ['wikitags'] = the number of 'wikistack' entries produced by the html tag * * ['wikistack'] = array(), is used to save the wiki markup for the linebreak handling (1 array = 1 html tag) * Each array entry contains the following keys: * - ['begin'] = array() of begin markups (1 style definition = 1 array entry) * - ['end'] = array() of end markups * * wiki_lbr = true if we must use '%%%' for linebreaks instead of '\n' */ $p = array('stack' => array(), 'listack' => array(), 'wikistack' => array(), 'wiki_lbr' => 0, 'first_td' => false, 'first_tr' => false); $this->walk_and_parse($htmlparser->content, $out_data, $p, ''); // Is some tags still opened? (It can be if HTML not valid, but this is not reason // to produce invalid wiki :) while (count($p['stack'])) { $e = end($p['stack']); $out_data .= $e['string']; array_pop($p['stack']); } // Unclosed lists r ignored... wiki have no special start/end lists syntax.... // OK. Things remains to do: // 1) fix linked images $out_data = preg_replace(',\[(.*)\|\(img src=(.*)\)\],mU', '{img src=$2 link=$1}', $out_data); // 2) fix remains images (not in links) $out_data = preg_replace(',\(img src=(.*)\),mU', '{img src=$1}', $out_data); // 3) remove empty lines $out_data = preg_replace(",[\n]+,mU", "\n", $out_data); // 4) remove nbsp's $out_data = preg_replace(", ,mU", " ", $out_data); return $out_data; } // end parse_html function get_new_page_attributes_from_parent_pages($page, $page_info) { global $wikilib, $tikilib; $new_page_attrs = array(); $parent_pages = $wikilib->get_parent_pages($page); $parent_pages_info = array(); foreach ($parent_pages as $a_parent_page_name) { $this_parent_page_info = $tikilib->get_page_info($a_parent_page_name); $parent_pages_info[] = $this_parent_page_info; } $new_page_attrs = $this->get_newpage_language_from_parent_page($page, $page_info, $parent_pages_info, $new_page_attrs); // Note: in the future, may add some methods below to guess things like // categories, workspaces, etc... return $new_page_attrs; } function get_newpage_language_from_parent_page($page, $page_info, $parent_pages_info, $new_page_attrs) { if (!isset($page_info['lang'])) { $lang = null; foreach ($parent_pages_info as $this_parent_page_info) { if (isset($this_parent_page_info['lang'])) { if ($lang != null and $lang != $this_parent_page_info['lang']) { // If more than one parent pages and they have different languages // then we can't guess which is the right one. $lang = null; break; } else { $lang = $this_parent_page_info['lang']; } } } if ($lang != null) { $new_page_attrs['lang'] = $lang; } } return $new_page_attrs; } } global $editlib; $editlib = new EditLib;
© 2017 -
ZeroByte.ID
.