diff --git a/AppKit/CPAnimation.j b/AppKit/CPAnimation.j index 712d5f7af..032a05df9 100644 --- a/AppKit/CPAnimation.j +++ b/AppKit/CPAnimation.j @@ -300,13 +300,47 @@ ACTUAL_FRAME_RATE = 0; */ - (float)currentValue { + var t = [self currentProgress]; + if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)]) - return [_delegate animation:self valueForProgress:_progress]; + return [_delegate animation:self valueForProgress:t]; - if (_animationCurve == CPAnimationLinear) - return _progress; - - alert("IMPLEMENT ANIMATION CURVES!!!"); + var c1 = [], + c2 = []; + + [_timingFunction getControlPointAtIndex:1 values:c1]; + [_timingFunction getControlPointAtIndex:2 values:c2]; + + return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration); } @end + +// currently used function to determine time +// 1:1 conversion to js from webkit source files +// UnitBezier.h, WebCore_animation_AnimationBase.cpp +var CubicBezierAtTime = function CubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration) +{ + var ax=0,bx=0,cx=0,ay=0,by=0,cy=0; + // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. + function sampleCurveX(t) {return ((ax*t+bx)*t+cx)*t;}; + function sampleCurveY(t) {return ((ay*t+by)*t+cy)*t;}; + function sampleCurveDerivativeX(t) {return (3.0*ax*t+2.0*bx)*t+cx;}; + // The epsilon value to pass given that the animation is going to run over |duration| seconds. The longer the animation, the more precision is needed in the timing function result to avoid ugly discontinuities. + function solveEpsilon(duration) {return 1.0/(200.0*duration);}; + function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));}; + // Given an x value, find a parametric value it came from. + function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i; + function fabs(n) {if(n>=0) {return n;}else {return 0-n;}}; + // First try a few iterations of Newton's method -- normally very fast. + for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)t1) {return t1;} + while(t0x2) {t0=t2;}else {t1=t2;} t2=(t1-t0)*.5+t0;} + return t2; // Failure. + }; + // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). + cx=3.0*p1x; bx=3.0*(p2x-p1x)-cx; ax=1.0-cx-bx; cy=3.0*p1y; by=3.0*(p2y-p1y)-cy; ay=1.0-cy-by; + // Convert from input time to parametric value in curve, then from that to output time. + return solve(t, solveEpsilon(duration)); +}; diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index 26aa821e6..72f88a420 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -719,9 +719,40 @@ CPRunContinuesResponse = -1002; */ - (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo { + var styleMask = [aSheet styleMask]; + if (!(styleMask & CPDocModalWindowMask)) + { + [CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"]; + return; + } + [aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo]; } +- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode +{ + var count = [_windows count]; + + while (--count >= 0) + { + var aWindow = [_windows objectAtIndex:count]; + var context = aWindow._sheetContext; + + if (context != nil && context["sheet"] === sheet) + { + context["returnCode"] = returnCode; + [aWindow _detachSheetWindow]; + return; + } + } +} + +- (void)endSheet:(CPWindow)sheet +{ + [self endSheet:sheet returnCode:0]; +} + + - (CPArray)arguments { if(_fullArgsString != window.location.hash) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 87d11f5f7..d00f3aa6f 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -293,14 +293,6 @@ var CPControlBlackColor = [CPColor blackColor]; _previousTrackingLocation = currentLocation; } -- (void)performClick:(id)sender -{ - [self highlight:YES]; - [self setState:[self nextState]]; - [self sendAction:[self action] to:[self target]]; - [self highlight:NO]; -} - - (void)setState:(int)state { } @@ -310,6 +302,14 @@ var CPControlBlackColor = [CPColor blackColor]; return 0; } +- (void)performClick:(id)sender +{ + [self highlight:YES]; + [self setState:[self nextState]]; + [self sendAction:[self action] to:[self target]]; + [self highlight:NO]; +} + - (unsigned)mouseDownFlags { return _trackingMouseDownFlags; diff --git a/AppKit/CPPanel.j b/AppKit/CPPanel.j index 65dc9b177..61480d50a 100644 --- a/AppKit/CPPanel.j +++ b/AppKit/CPPanel.j @@ -46,6 +46,13 @@ CPCancelButton = 0;
  • A panel can be made to work even when there's an attention panel on-screen. This permits actions within the panel to affect the attention panel.
  • */ + +/* + @global + @class CPWindow +*/ +CPDocModalWindowMask = 1 << 6; + @implementation CPPanel : CPWindow { BOOL _becomesKeyOnlyIfNeeded; diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 7dc79c3ca..0b0d1bee0 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -176,13 +176,13 @@ CPWindowWillCloseNotification = @"CPWindowWillCloseNotification"; CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification"; CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification"; CPWindowDidMoveNotification = @"CPWindowDidMoveNotification"; - +CPWindowWillBeginSheetNotification = @"CPWindowWillBeginSheetNotification"; +CPWindowDidEndSheetNotification = @"CPWindowDidEndSheetNotification"; CPWindowShadowStyleStandard = 0; CPWindowShadowStyleMenu = 1; CPWindowShadowStylePanel = 2; - var SHADOW_MARGIN_LEFT = 20.0, SHADOW_MARGIN_RIGHT = 19.0, SHADOW_MARGIN_TOP = 10.0, @@ -309,6 +309,10 @@ var CPWindowSaveImage = nil, BOOL _isFullPlatformWindow; _CPWindowFullPlatformWindowSession _fullPlatformWindowSession; + + CPDictionary _sheetContext; + CPWindow _parentView; + BOOL _isSheet; } /* @@ -363,6 +367,7 @@ CPTexturedBackgroundWindowMask _isFullPlatformWindow = NO; _registeredDraggedTypes = [CPSet set]; _registeredDraggedTypesArray = []; + _isSheet = NO; // Set up our window number. _windowNumber = [CPApp._windows count]; @@ -439,7 +444,10 @@ CPTexturedBackgroundWindowMask else if (aStyleMask === CPBorderlessWindowMask) return _CPBorderlessWindowView; - + + else if (aStyleMask & CPDocModalWindowMask) + return _CPDocModalWindowView; + return _CPStandardWindowView; } @@ -1722,57 +1730,150 @@ CPTexturedBackgroundWindowMask */ } +- (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve +{ + var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; + [animation setDelegate:delegate]; + [animation setAnimationCurve:curve]; + [animation setDuration:duration]; + [animation startAnimation]; +} + /* @ignore */ - (void)_setAttachedSheetFrameOrigin { // Position the sheet above the contentRect. + var attachedSheet = [self attachedSheet]; var contentRect = [[self contentView] frame], - sheetFrame = CGRectMakeCopy([_attachedSheet frame]); + sheetFrame = CGRectMakeCopy([attachedSheet frame]); - sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect); - sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0); + sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect); + sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0); - [_attachedSheet setFrameOrigin:sheetFrame.origin]; -} - -/* @ignore */ -- (void)_animateAttachedSheet -{ -/* NSWindow *sheet = [sheetContext sheet]; - NSRect sheetFrame; - - [_sheetContext autorelease]; - _sheetContext=[sheetContext retain]; - - [self _setSheetOrigin]; - sheetFrame = [sheet frame]; - - [(NSWindowBackgroundView *)[sheet _backgroundView] setBorderType:NSButtonBorder]; - [[sheet contentView] setAutoresizesSubviews:NO]; - [[sheet contentView] setAutoresizingMask:NSViewNotSizable]; - -// [(NSWindowBackgroundView *)[sheet _backgroundView] cacheImageForAnimation]; - - [_attachedSheet setFrame:CPRectMake(CGRectGetMinX(sheetFrame), CGRectGetMinY(sheetFrame), CGRectGetWidth(sheetFrame), 0.0) display:YES]; - [sheet setFrame:NSMakeRect(sheetFrame.origin.x, NSMaxY([self frame]), sheetFrame.size.width, 0) display:YES]; - [self _setSheetOriginAndFront]; - - [sheet setFrame:sheetFrame display:YES animate:YES];*/ + [attachedSheet setFrameOrigin:sheetFrame.origin]; } /* @ignore */ - (void)_attachSheet:(CPWindow)aSheet modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo { - // Set this as our attached sheet. - _attachedSheet = aSheet; + var sheetFrame = [aSheet frame]; + + _sheetContext = {"sheet":aSheet, "modalDelegate":aModalDelegate, "endSelector":aDidEndSelector, "contextInfo":aContextInfo, "frame":CGRectMakeCopy(sheetFrame), "returnCode":-1, "opened": NO}; - // If a window is ever run as a sheet, then it's sheet bit is set to YES. + [self _attachSheetWindow:aSheet]; +} + +/* @ignore */ +- (void)_attachSheetWindow:(CPWindow)aSheet +{ + var sheetFrame = [aSheet frame], + frame = [self frame], + sheetContent = [aSheet contentView]; + + [self _setUpMasksForView:sheetContent]; + aSheet._isSheet = YES; + aSheet._parentView = self; - [self _setAttachedSheetFrameOrigin]; + var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width)/2), + originy = frame.origin.y + [[self contentView] frame].origin.y, + startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0), + endFrame = CGRectMake(originx, originy, sheetFrame.size.width, sheetFrame.size.height); + + [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self]; + [CPApp runModalForWindow:aSheet]; - // Place this window above ourselves. - [_platformWindow order:CPWindowAbove window:aSheet relativeTo:self]; + [aSheet orderFront:self]; + [aSheet setFrame:startFrame]; + _sheetContext["opened"] = YES; + + [aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut]; + + // Should run the main loop here until _isAnimating = FALSE + [aSheet becomeKeyWindow]; +} + +/* @ignore */ +- (void)_detachSheetWindow +{ + var sheet = [self attachedSheet], + startFrame = [sheet frame], + endFrame = CGRectMakeCopy(startFrame); + + endFrame.size.height = 0; + + _sheetContext["frame"] = startFrame; + + var sheetContent = [sheet contentView]; + [self _setUpMasksForView:sheetContent]; + + _sheetContext["opened"] = NO; + [sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseIn]; +} + +/* @ignore */ +- (void)animationDidEnd:(id)anim +{ + var sheet = _sheetContext["sheet"]; + if (anim._window != sheet) + return; + + var sheetContent = [sheet contentView]; + + if (_sheetContext["opened"] === YES) + { + [self _restoreMasksForView:sheetContent]; + return; + } + + [CPApp stopModal]; + [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self]; + + [sheet orderOut:self]; + + var lastFrame = _sheetContext["frame"]; + [sheet setFrame:lastFrame]; + + [self _restoreMasksForView:sheetContent]; + + var delegate = _sheetContext["modalDelegate"], + endSelector = _sheetContext["endSelector"]; + + if (delegate != nil && endSelector != nil) + objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]); + + _sheetContext = nil; + sheet._parentView = nil; +} + +- (void)_setUpMasksForView:(CPView)aView +{ + var views = [CPArray arrayWithArray:[aView subviews]]; + [views addObject:aView]; + + for (var i = 0, count = [views count]; i < count; i++) + { + var view = [views objectAtIndex:i], + mask = [view autoresizingMask], + maskToAdd = (mask & CPViewMinYMargin) ? 128 : CPViewMinYMargin; + + [view setAutoresizingMask:(mask | maskToAdd)]; + } +} + +- (void)_restoreMasksForView:(CPView)aView +{ + var views = [CPArray arrayWithArray:[aView subviews]]; + [views addObject:aView]; + + for (var i = 0, count = [views count]; i < count; i++) + { + var view = [views objectAtIndex:i], + mask = [view autoresizingMask], + maskToRemove = (mask & 128) ? 128 : CPViewMinYMargin; + + [view setAutoresizingMask:(mask & (~ maskToRemove))]; + } } /*! @@ -1780,7 +1881,10 @@ CPTexturedBackgroundWindowMask */ - (CPWindow)attachedSheet { - return _attachedSheet; + if (_sheetContext === nil) + return nil; + + return _sheetContext["sheet"]; } /*! @@ -2225,6 +2329,7 @@ function _CPWindowFullPlatformWindowSessionMake(aWindowView, aContentRect, hasSh @import "_CPWindowView.j" @import "_CPStandardWindowView.j" +@import "_CPDocModalWindowView.j" @import "_CPHUDWindowView.j" @import "_CPBorderlessWindowView.j" @import "_CPBorderlessBridgeWindowView.j" diff --git a/AppKit/CPWindow/_CPDocModalWindowView.j b/AppKit/CPWindow/_CPDocModalWindowView.j new file mode 100644 index 000000000..9db0ee9c7 --- /dev/null +++ b/AppKit/CPWindow/_CPDocModalWindowView.j @@ -0,0 +1,50 @@ + +@import "_CPWindowView.j" + +var _CPStandardWindowViewBodyBackgroundColor = nil; + +@implementation _CPDocModalWindowView : _CPWindowView +{ + CPView _bodyView; +} + ++ (CPColor)bodyBackgroundColor +{ + if (!_CPStandardWindowViewBodyBackgroundColor) + _CPStandardWindowViewBodyBackgroundColor = [CPColor colorWithWhite:0.96 alpha:1.0]; + + return _CPStandardWindowViewBodyBackgroundColor; +} + +- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask +{ + self = [super initWithFrame:aFrame styleMask:aStyleMask]; + + if (self) + { + var theClass = [self class], + bounds = [self bounds]; + + _bodyView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), CGRectGetHeight(bounds))]; + + [_bodyView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; + [_bodyView setBackgroundColor:[theClass bodyBackgroundColor]]; + [_bodyView setHitTests:NO]; + + [self addSubview:_bodyView]; + } + + return self; +} + +- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect +{ + return aFrameRect; +} + +- (CGRect)frameRectForContentRect:(CGRect)aContentRect +{ + return aContentRect; +} + +@end \ No newline at end of file diff --git a/AppKit/CPWindow/_CPWindowView.j b/AppKit/CPWindow/_CPWindowView.j index 890044daa..5231016f6 100644 --- a/AppKit/CPWindow/_CPWindowView.j +++ b/AppKit/CPWindow/_CPWindowView.j @@ -135,7 +135,14 @@ var _CPWindowViewResizeIndicatorImage = nil; } else if (type === CPLeftMouseDragged) - [theWindow setFrameSize:CGSizeMake(CGRectGetWidth(_resizeFrame) + location.x - CGRectGetMinX(_resizeFrame), CGRectGetHeight(_resizeFrame) + location.y - CGRectGetMinY(_resizeFrame))]; + { + var newSize = CGSizeMake(CGRectGetWidth(_resizeFrame) + location.x - CGRectGetMinX(_resizeFrame), CGRectGetHeight(_resizeFrame) + location.y - CGRectGetMinY(_resizeFrame)); + + if (theWindow._isSheet && theWindow._parentView && (theWindow._frame.size.width !== newSize.width)) + [theWindow._parentView _setAttachedSheetFrameOrigin]; + + [theWindow setFrameSize:newSize]; + } [CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; } diff --git a/Tests/AttachedSheet/AppController.j b/Tests/AttachedSheet/AppController.j new file mode 100644 index 000000000..d5ef53467 --- /dev/null +++ b/Tests/AttachedSheet/AppController.j @@ -0,0 +1,89 @@ +/* + * AppController.j + * AttachedSheet + * + * Created by Cacaodev on August 1, 2009. + * Copyright 2009, Your Company All rights reserved. + */ + +@import + +@implementation AppController : CPObject +{ + CPWindow window; + CPWindow sheet; + CPTextField textField; +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + window = [[CPWindow alloc] initWithContentRect:CGRectMake(100,100,500,300) styleMask:CPResizableWindowMask], + contentView = [window contentView]; + + sheet = [[CPWindow alloc] initWithContentRect:CGRectMake(0,0,300,100) styleMask:CPDocModalWindowMask|CPResizableWindowMask]; + // [sheet setMinSize:CGSizeMake(300,100)]; + + var sheetContent = [sheet contentView]; + + textField = [[CPTextField alloc] initWithFrame:CGRectMake(10,30,280,30)]; + [textField setEditable:YES]; + [textField setBezeled:YES]; + [textField setAutoresizingMask:CPViewWidthSizable]; + + var okButton = [[CPButton alloc] initWithFrame:CGRectMake(230,70,50,24)]; + [okButton setTitle:"OK"]; + [okButton setTarget:self]; + [okButton setTag:1]; + [okButton setAction:@selector(closeSheet:)]; + [okButton setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin]; + + var cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(120,70,100,24)]; + [cancelButton setTitle:"Cancel"]; + [cancelButton setTarget:self]; + [cancelButton setTag:0]; + [cancelButton setAction:@selector(closeSheet:)]; + [cancelButton setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin]; + + [sheetContent addSubview:textField]; + [sheetContent addSubview:okButton]; + [sheetContent addSubview:cancelButton]; + + var displayButton = [[CPButton alloc] initWithFrame:CGRectMake(200,150,100,24)]; + [displayButton setTitle:"Display Sheet"]; + [displayButton setTarget:self]; + [displayButton setAction:@selector(displaySheet:)]; + [contentView addSubview:displayButton]; + + [window orderFront:self] +} + +- (void)displaySheet:(id)sender +{ + [textField setStringValue:""]; + [sheet makeFirstResponder:textField]; + + [CPApp beginSheet:sheet modalForWindow:window modalDelegate:self didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) contextInfo:nil]; +} + +- (void)alertDidEnd:(CPWindow)sheet returnCode:(int)returnCode contextInfo:(id)contextInfo +{ + CPLogConsole(_cmd+" returnCode " + returnCode); +} + +- (void)closeSheet:(id)sender +{ + [CPApp endSheet:sheet returnCode:[sender tag]]; +} + +- (void)didEndSheet:(CPWindow)sheet returnCode:(int)returnCode contextInfo:(id)contextInfo +{ + var str = [textField stringValue]; + + [sheet orderOut:self]; + if (returnCode == CPOKButton && [str length] > 0) + { + [window setTitle:str]; + } +} + +@end \ No newline at end of file diff --git a/Tests/AttachedSheet/Info.plist b/Tests/AttachedSheet/Info.plist new file mode 100644 index 000000000..143e86dbd --- /dev/null +++ b/Tests/AttachedSheet/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + FullOfSheet + CPPrincipalClass + CPApplication + + diff --git a/Tests/AttachedSheet/Rakefile b/Tests/AttachedSheet/Rakefile new file mode 100644 index 000000000..3fc1dbfa1 --- /dev/null +++ b/Tests/AttachedSheet/Rakefile @@ -0,0 +1,25 @@ + +require 'objective-j' +require 'objective-j/bundletask' + +if !ENV['CONFIG'] + ENV['CONFIG'] = 'Debug' +end + +ObjectiveJ::BundleTask.new(:SplitView) do |t| + t.name = 'SplitView' + t.identifier = 'com.yourcompany.SplitView' + t.version = '1.0' + t.author = 'Your Company' + t.email = 'feedback @nospam@ yourcompany.com' + t.summary = 'SplitView' + t.sources = FileList['*.j'] + t.resources = FileList['Resources/*'] + t.index_file = 'index.html' + t.info_plist = 'Info.plist' + t.build_path = File.join('Build', ENV['CONFIG'], 'SplitView') + t.flag = '-DDEBUG' if ENV['CONFIG'] == 'Debug' + t.flag = '-O' if ENV['CONFIG'] == 'Release' +end + +task :default => [:SplitView] diff --git a/Tests/AttachedSheet/Resources/spinner.gif b/Tests/AttachedSheet/Resources/spinner.gif new file mode 100644 index 000000000..06dbc2bc2 Binary files /dev/null and b/Tests/AttachedSheet/Resources/spinner.gif differ diff --git a/Tests/AttachedSheet/index-debug.html b/Tests/AttachedSheet/index-debug.html new file mode 100644 index 000000000..4daefda17 --- /dev/null +++ b/Tests/AttachedSheet/index-debug.html @@ -0,0 +1,83 @@ + + + + + + + + Attached Sheet + + + + + + + + + + + + + +
    + + + +
    + + + diff --git a/Tests/AttachedSheet/index.html b/Tests/AttachedSheet/index.html new file mode 100644 index 000000000..d44a75d39 --- /dev/null +++ b/Tests/AttachedSheet/index.html @@ -0,0 +1,69 @@ + + + + + + + + Attached Sheet + + + + + + + + + + + + +
    + + + +
    + + + + diff --git a/Tests/AttachedSheet/main.j b/Tests/AttachedSheet/main.j new file mode 100755 index 000000000..b67c4550b --- /dev/null +++ b/Tests/AttachedSheet/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * SplitView + * + * Created by You on August 1, 2009. + * Copyright 2009, Your Company All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +}