forked from minhngoc25a/freetype2
Mac demo support stuff.
This commit is contained in:
parent
2e8482b31d
commit
858fd5f7f1
|
@ -0,0 +1,22 @@
|
|||
This folder contains supporting code and CodeWarrior Pro 4 project
|
||||
files to build the FreeType demo programs ftlint and ftview for MacOS.
|
||||
|
||||
Building
|
||||
To build these apps, you'll first need to build the FreeType library
|
||||
(see config/mac). The applications get built in the demos/bin folder.
|
||||
|
||||
Notes
|
||||
Since the Mac doesn't have the notion of argc/argv, we'll emulate
|
||||
this: each file dropped onto the application will be translated
|
||||
to a command line argument. Both ftlint and ftview take a ppem
|
||||
value as their first command line argument: for the Mac version
|
||||
this has been hard-coded into the source. Also: the additional
|
||||
options for ftview cannot be set.
|
||||
|
||||
Have fun with FreeType on the Mac!
|
||||
|
||||
Just van Rossum, <just@letterror.com>
|
||||
|
||||
DISCLAIMER: this subdirectory is *not* being maintained by the
|
||||
FreeType team, but by Just van Rossum. It's being released under
|
||||
the same terms as FreeType (see license.txt).
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,59 @@
|
|||
/* minimal Mac wrapper for the ftlint.c program */
|
||||
|
||||
|
||||
int original_main( int argc, char** argv );
|
||||
|
||||
/* We rename the original main() program to original_main,
|
||||
so we can provide a wrapper around it */
|
||||
#define main original_main
|
||||
#include "ftlint.c"
|
||||
#undef main
|
||||
|
||||
|
||||
#define PPEM "24" /* hard-code the ppem size */
|
||||
|
||||
|
||||
#include <SIOUX.h>
|
||||
#include "getargv.h"
|
||||
#include <Windows.h>
|
||||
#include <Dialogs.h>
|
||||
#include <Fonts.h>
|
||||
#include <TextEdit.h>
|
||||
|
||||
static void
|
||||
init_toolbox()
|
||||
{
|
||||
InitGraf(&qd.thePort);
|
||||
InitFonts();
|
||||
InitWindows();
|
||||
TEInit();
|
||||
InitDialogs((long)0);
|
||||
InitMenus();
|
||||
InitCursor();
|
||||
SIOUXSettings.asktosaveonclose = 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int argc, i;
|
||||
char** argv;
|
||||
|
||||
init_toolbox();
|
||||
|
||||
/* put paths of all files dropped onto the app into argv */
|
||||
argc = FTMac_GetArgv(&argv);
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("Please drop one or more font files onto the app (but quit first!)\n");
|
||||
exit(1);
|
||||
}
|
||||
/* move argv[1:] to argv[2:] and fill in the ppem arg */
|
||||
for (i = argc; i > 1; i--)
|
||||
{
|
||||
argv[i] = argv[i-1];
|
||||
}
|
||||
argc++;
|
||||
argv[1] = PPEM;
|
||||
/* call the original main() program */
|
||||
original_main(argc, argv);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* minimal Mac wrapper for the ftview.c program */
|
||||
|
||||
|
||||
int original_main( int argc, char** argv );
|
||||
|
||||
/* We rename the original main() program to original_main,
|
||||
so we can provide a wrapper around it */
|
||||
#define main original_main
|
||||
#include "ftview.c"
|
||||
#undef main
|
||||
|
||||
|
||||
#define PPEM "24" /* hard-code the ppem size */
|
||||
|
||||
|
||||
#include <SIOUX.h>
|
||||
#include "getargv.h"
|
||||
#include <Windows.h>
|
||||
#include <Dialogs.h>
|
||||
#include <Fonts.h>
|
||||
#include <TextEdit.h>
|
||||
|
||||
static void
|
||||
init_toolbox()
|
||||
{
|
||||
InitGraf(&qd.thePort);
|
||||
InitFonts();
|
||||
InitWindows();
|
||||
TEInit();
|
||||
InitDialogs((long)0);
|
||||
InitMenus();
|
||||
InitCursor();
|
||||
SIOUXSettings.asktosaveonclose = 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int argc, i;
|
||||
char** argv;
|
||||
|
||||
init_toolbox();
|
||||
|
||||
/* put paths of all files dropped onto the app into argv */
|
||||
argc = FTMac_GetArgv(&argv);
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("Please drop one or more font files onto the app (but quit first!)\n");
|
||||
exit(1);
|
||||
}
|
||||
/* move argv[1:] to argv[2:] and fill in the ppem arg */
|
||||
for (i = argc; i > 1; i--)
|
||||
{
|
||||
argv[i] = argv[i-1];
|
||||
}
|
||||
argc++;
|
||||
argv[1] = PPEM;
|
||||
/* call the original main() program */
|
||||
original_main(argc, argv);
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
/***********************************************************
|
||||
Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
|
||||
The Netherlands.
|
||||
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the names of Stichting Mathematisch
|
||||
Centrum or CWI not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior permission.
|
||||
|
||||
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
||||
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
/* Construct argc and argv for main() by using Apple Events */
|
||||
/* From Jack's implementation for STDWIN */
|
||||
|
||||
/* Modified for use with FreeType from MacPython's macgetargv.c
|
||||
by Just van Rossum <just@letterror.com> */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "getargv.h"
|
||||
|
||||
#include <Types.h>
|
||||
#include <Files.h>
|
||||
#include <Events.h>
|
||||
#include <Processes.h>
|
||||
#include <Errors.h>
|
||||
#include <AppleEvents.h>
|
||||
#include <AEObjects.h>
|
||||
|
||||
#ifdef GENERATINGCFM /* Defined to 0 or 1 in Universal headers */
|
||||
#define HAVE_UNIVERSAL_HEADERS
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_UNIVERSAL_HEADERS
|
||||
#define NewAEEventHandlerProc(x) (x)
|
||||
#define AEEventHandlerUPP EventHandlerProcPtr
|
||||
#endif
|
||||
|
||||
static int arg_count;
|
||||
static char *arg_vector[256];
|
||||
static char app_name[256];
|
||||
static int app_name_inited;
|
||||
|
||||
|
||||
/* Duplicate a string to the heap. */
|
||||
|
||||
static char *
|
||||
strdup(char *src)
|
||||
{
|
||||
char *dst = malloc(strlen(src) + 1);
|
||||
if (dst)
|
||||
strcpy(dst, src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
/* Given an FSSpec, return the FSSpec of the parent folder */
|
||||
|
||||
static OSErr
|
||||
get_folder_parent (FSSpec * fss, FSSpec * parent)
|
||||
{
|
||||
CInfoPBRec rec;
|
||||
short err;
|
||||
|
||||
* parent = * fss;
|
||||
rec.hFileInfo.ioNamePtr = parent->name;
|
||||
rec.hFileInfo.ioVRefNum = parent->vRefNum;
|
||||
rec.hFileInfo.ioDirID = parent->parID;
|
||||
rec.hFileInfo.ioFDirIndex = -1;
|
||||
rec.hFileInfo.ioFVersNum = 0;
|
||||
if (err = PBGetCatInfoSync (& rec))
|
||||
return err;
|
||||
parent->parID = rec.dirInfo.ioDrParID;
|
||||
/* parent->name[0] = 0; */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Given an FSSpec return a full, colon-separated pathname */
|
||||
|
||||
static OSErr
|
||||
FTMac_GetFullPath (FSSpec *fss, char *buf)
|
||||
{
|
||||
short err;
|
||||
FSSpec fss_parent, fss_current;
|
||||
char tmpbuf[256];
|
||||
int plen;
|
||||
|
||||
fss_current = *fss;
|
||||
plen = fss_current.name[0];
|
||||
memcpy(buf, &fss_current.name[1], plen);
|
||||
buf[plen] = 0;
|
||||
/* Special case for disk names */
|
||||
if ( fss_current.parID <= 1 ) {
|
||||
buf[plen++] = ':';
|
||||
buf[plen] = 0;
|
||||
return 0;
|
||||
}
|
||||
while (fss_current.parID > 1) {
|
||||
/* Get parent folder name */
|
||||
if (err = get_folder_parent(&fss_current, &fss_parent))
|
||||
return err;
|
||||
fss_current = fss_parent;
|
||||
/* Prepend path component just found to buf */
|
||||
plen = fss_current.name[0];
|
||||
if (strlen(buf) + plen + 1 > 256) {
|
||||
/* Oops... Not enough space (shouldn't happen) */
|
||||
*buf = 0;
|
||||
return -1;
|
||||
}
|
||||
memcpy(tmpbuf, &fss_current.name[1], plen);
|
||||
tmpbuf[plen] = ':';
|
||||
strcpy(&tmpbuf[plen+1], buf);
|
||||
strcpy(buf, tmpbuf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize name of current application */
|
||||
|
||||
static OSErr
|
||||
init_app_name()
|
||||
{
|
||||
ProcessSerialNumber currentPSN;
|
||||
ProcessInfoRec info;
|
||||
OSErr err;
|
||||
FSSpec appSpec;
|
||||
|
||||
if ( app_name_inited ) return 0;
|
||||
currentPSN.highLongOfPSN = 0;
|
||||
currentPSN.lowLongOfPSN = kCurrentProcess;
|
||||
info.processInfoLength = sizeof(ProcessInfoRec);
|
||||
info.processName = NULL;
|
||||
info.processAppSpec = &appSpec;
|
||||
if ( err=GetProcessInformation(¤tPSN, &info))
|
||||
return err;
|
||||
strncpy(app_name, (char*)appSpec.name + 1, appSpec.name[0]);
|
||||
app_name[appSpec.name[0]] = '\0';
|
||||
app_name_inited = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Check that there aren't any args remaining in the event */
|
||||
|
||||
static OSErr
|
||||
get_missing_params(AppleEvent *theAppleEvent)
|
||||
{
|
||||
DescType theType;
|
||||
Size actualSize;
|
||||
OSErr err;
|
||||
|
||||
err = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard,
|
||||
&theType, nil, 0, &actualSize);
|
||||
if (err == errAEDescNotFound)
|
||||
return noErr;
|
||||
else
|
||||
return errAEEventNotHandled;
|
||||
}
|
||||
|
||||
static int got_one; /* Flag that we can stop getting events */
|
||||
|
||||
|
||||
/* Handle the Print or Quit events (by failing) */
|
||||
|
||||
static pascal OSErr
|
||||
handle_not(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
|
||||
{
|
||||
#pragma unused (reply, refCon)
|
||||
got_one = 1;
|
||||
return errAEEventNotHandled;
|
||||
}
|
||||
|
||||
|
||||
/* Handle the Open Application event (by ignoring it) */
|
||||
|
||||
static pascal OSErr
|
||||
handle_open_app(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
|
||||
{
|
||||
#pragma unused (reply, refCon)
|
||||
#if 0
|
||||
/* Test by Jack: would removing this facilitate debugging? */
|
||||
got_one = 1;
|
||||
#endif
|
||||
return get_missing_params(theAppleEvent);
|
||||
}
|
||||
|
||||
|
||||
/* Handle the Open Document event, by adding an argument */
|
||||
|
||||
static pascal OSErr
|
||||
handle_open_doc(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
|
||||
{
|
||||
#pragma unused (reply, refCon)
|
||||
OSErr err;
|
||||
AEDescList doclist;
|
||||
AEKeyword keywd;
|
||||
DescType rttype;
|
||||
long i, ndocs, size;
|
||||
FSSpec fss;
|
||||
char path[256];
|
||||
|
||||
got_one = 1;
|
||||
if (err = AEGetParamDesc(theAppleEvent,
|
||||
keyDirectObject, typeAEList, &doclist))
|
||||
return err;
|
||||
if (err = get_missing_params(theAppleEvent))
|
||||
return err;
|
||||
if (err = AECountItems(&doclist, &ndocs))
|
||||
return err;
|
||||
for(i = 1; i <= ndocs; i++) {
|
||||
err = AEGetNthPtr(&doclist, i, typeFSS,
|
||||
&keywd, &rttype, &fss, sizeof(fss), &size);
|
||||
if (err)
|
||||
break;
|
||||
FTMac_GetFullPath(&fss, path);
|
||||
arg_vector[arg_count++] = strdup(path);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Install standard core event handlers */
|
||||
static AEEventHandlerUPP open_doc_upp;
|
||||
static AEEventHandlerUPP open_app_upp;
|
||||
static AEEventHandlerUPP not_upp;
|
||||
|
||||
static void
|
||||
set_ae_handlers()
|
||||
{
|
||||
open_doc_upp = NewAEEventHandlerProc(handle_open_doc);
|
||||
open_app_upp = NewAEEventHandlerProc(handle_open_app);
|
||||
not_upp = NewAEEventHandlerProc(handle_not);
|
||||
|
||||
AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
|
||||
open_app_upp, 0L, false);
|
||||
AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
|
||||
open_doc_upp, 0L, false);
|
||||
AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
|
||||
not_upp, 0L, false);
|
||||
AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
|
||||
not_upp, 0L, false);
|
||||
}
|
||||
|
||||
/* Uninstall standard core event handlers */
|
||||
|
||||
static void
|
||||
reset_ae_handlers()
|
||||
{
|
||||
AERemoveEventHandler(kCoreEventClass, kAEOpenApplication,
|
||||
open_app_upp, false);
|
||||
AERemoveEventHandler(kCoreEventClass, kAEOpenDocuments,
|
||||
open_doc_upp, false);
|
||||
AERemoveEventHandler(kCoreEventClass, kAEPrintDocuments,
|
||||
not_upp, false);
|
||||
AERemoveEventHandler(kCoreEventClass, kAEQuitApplication,
|
||||
not_upp, false);
|
||||
}
|
||||
|
||||
/* Wait for events until a core event has been handled */
|
||||
|
||||
static void
|
||||
event_loop()
|
||||
{
|
||||
EventRecord event;
|
||||
int n;
|
||||
int ok;
|
||||
|
||||
got_one = 0;
|
||||
for (n = 0; n < 100 && !got_one; n++) {
|
||||
SystemTask();
|
||||
ok = GetNextEvent(everyEvent, &event);
|
||||
if (ok && event.what == kHighLevelEvent) {
|
||||
AEProcessAppleEvent(&event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the argv vector, return argc. See macgetargv.h for more doco. */
|
||||
|
||||
int
|
||||
FTMac_GetArgv(pargv)
|
||||
char ***pargv;
|
||||
{
|
||||
|
||||
arg_count = 0;
|
||||
(void)init_app_name();
|
||||
arg_vector[arg_count++] = strdup(app_name);
|
||||
|
||||
set_ae_handlers();
|
||||
event_loop();
|
||||
reset_ae_handlers();
|
||||
|
||||
arg_vector[arg_count] = NULL;
|
||||
|
||||
*pargv = arg_vector;
|
||||
return arg_count;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
<Function>
|
||||
FTMac_GetArgv
|
||||
|
||||
<Description>
|
||||
argc/argv emulation for the Mac. Converts files dropped
|
||||
onto the application to full paths, and stuff them into
|
||||
argv.
|
||||
|
||||
<Output>
|
||||
pargv :: a pointer to an argv array. The array doesn't need to
|
||||
exist before calling this function.
|
||||
|
||||
<Return>
|
||||
The number of files dropped onto the app (ie. argc)
|
||||
*/
|
||||
|
||||
int FTMac_GetArgv(char ***pargv);
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
(This file must be converted with BinHex 4.0)
|
||||
:$(*PFfpeFQ0P,R0TG!"6594%8dP8)3%!!!!'[!!!!!!REP0*9#%!!J!!"Vab6'&
|
||||
e!RX!!!!@EhX0!!YQG'aTER3ZFR0bB`K"ST!!!%9qHJ!!!)!!!!!!#%PXcPl2#BB
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!"R`!!!!$rrrrrFR0bBe*6483"!,6HlZHdhZmk!!!
|
||||
"Q3!!!!!!!!%C!!!!!"2I!!!!!!!!!!#2I4%!#"`XG3MLeZTM1d$2c[ec0aXql5S
|
||||
ShPIL[&U,h14S@fT@KjEj-dK+IjNHBG)R-N9+9!`J2MP%TSHT%#Nd-qT*elC3-#N
|
||||
4JA)Hkc6qlRVSqDHb&A*3a9&1cdmjhEbBUHN9ad&X+`E&1ceI!Y68j0ki6qFA)(r
|
||||
b,FRGeI4f6k%5&4RNVXbJD-emb41U6CZldibq,@I[0+0[hAC1Pd8qb1GJMXlkGX[
|
||||
Qi$6*5FhCV+hMcp9GjDB!CG6%FFi-Y%hSD+RR#(40DQ1''@VI1VRml-&F9CdAA5b
|
||||
'mAYaP!drhR!2h3*kJDG9FQ)R4mZIfD4`CM-&4Q9IJU0XbMdc06QfE,r!c)B,BXZ
|
||||
5lI0h(XbS`)*QmLcRP#B"!!!!$3!,CR4fD@9h,R*cFQ-)3D+3!!"&IRS!!!#!!!!
|
||||
!!!K*E-kIZJQ'!!!!!!!!!!!!!!!!!!!!&J!!!!!!!!!!rrrrrh*cFQ058d9%!3#
|
||||
dhZlRY0pi`J!!#Fd!!!!!!!!%V3!!!!#NcJ!!!!!!!!!!i8X,3,6cZVA1c0lNY)[
|
||||
f+j[)D@pq&ff8&[hml++YG5DRR()cQTfYCHr*j#YEf5Jc%CLIXrbFjqFX2cmr2dr
|
||||
ZTpFJfU$ca31a!b+85iiI35I(Bq'a#e!!VJ6J!#F!VSd!Nr('42m&cC%BQfS+kII
|
||||
X%,b5(HDLA-XlBDbP"ISMY'LUSfGRDkm!HhGl5NUk05!P)laE*h[lM)b!S+!8DhG
|
||||
VJA4q'GFk-X)*HFCMl1QrCp29l+`h+kl(I3FBqcaJl-h0E-YliEX#cZ%fH-9NHb2
|
||||
[J5A*h#if"qk@8jD%["I4@8lH[MDBr'c`$(5cE+ral1fF[*0$mqINR4`FEH`P-!"
|
||||
ZaYZ$[j86fKM'6M`k&3TTDRc[bEfDM@PAb0Zc`KL$6e6mrPk'RD,L)U0H$fC!XbD
|
||||
@b[N$+ecGH0iXmEpL-Vhq#F#BEGiV"UHAIc%8q2X*3m(RMaLFRfBcZ16HC5Mdq$C
|
||||
$iBFh'%`j9aPFlepL+(,[2%241fFBh,*1-"5lGC6"rHBKKZ,Apc&iA0[&81,+GSD
|
||||
5PlF`P,UiJF(c`PU'dZG@-ALGAFE`cZP&$0iRjc'816k,SHbaD3c[(TR%i(0i(%1
|
||||
jJk-BbZmIaP"Klb!'mqlq$"9hpQ@SY+-R3q9YGSBU@fd-96GhBI$GQ-V`h[S1$(l
|
||||
VNKLUV@R$8(ee!N10PDdBr*HhB+LjY"P$`1*)KX#&B3a"md-BDXeY`&"lGKf'pfI
|
||||
@BJLHAT1KcY4U$(8R9f@S0l%L3rhaj4JDM#h$d("dDBB24TCJD$5m'%2)8&H'aS0
|
||||
G'$iFk-33f[mP3eLrj`cKIA-CQ[4qb"$4mcj$T1-13j6p&N26c1X-dEBV$-h5,c)
|
||||
dlh+1iD1dd``aUFFC@R3m`Q$TF*!!)6Cj,d2,T*d-VGTZBiKVXjQKGH*kK[L%03`
|
||||
IakpJ5)KE`["*b`8-LCBj$*r'c'"Sdh`+`fI4%aMD4SeKq$aL"%05q"#'GU%$'*)
|
||||
Epf0ShkJh3iH'$SD8qTN-(HZQ-eL$daK5DhGNk"58c*!!&Y#@SE0r)N1Ak[%-AIe
|
||||
D-U6laM"N9)PQX&@+B1KQ$QA),0q)i3ZIqJcfXX%-hEf$'"aHrJ`p22dBHTDX`Y$
|
||||
,`mc3fpf(SBqE0d2I)Ti-AjSm'2S9FQ2ibYR%d,q!-m2A1KN-d2PQS$a)(L`2NBI
|
||||
+`q6KmJKjT$a+(Lf2NFI+iq6amJ4jSMa*RLa2NDI+dq6TmJajTMa,RLh2NHI+mq6
|
||||
jmJ*jSEa)AL`[NCI+bq6PmJTjTEa+ALer)kq4emVVj'rPpI)'HD1m5GiXEj'hbYr
|
||||
*fq6YmJljHhQR[%[H,Hq4pmVlj2hb!IQJI%Jq,2mJ(j'2bXIN(qAMmJRjT(a+2Lf
|
||||
INFr+2mRRj22b"IPRqD*m5EiXrb*INDr+eq4IjH[b$IQQr*Ym5liYCmQrbhINZr)
|
||||
pq3rj[T`YjmJ2j)Ib)rQar+HF+cq4RmV2j1IbAr,ImJ[jTIa+cVrAq2IZa#8h`e(
|
||||
[M,(L!aX+KPXLBSbe5VT9#0!Y3m18p"i1`e(jTiGr6K,QYpFN0E5riJD$A(+l,R'
|
||||
2l@@cfXefDrGZ2H`TeP*4GUXe[NqQe4`@CXjXRfje1+cr!`IL!!!:
|
Loading…
Reference in New Issue