text:
/*
 * Driver for Cocoa framework. This is a multiple display driver (one
 * Cocoa window is created for each Agar window).
 */

#include <agar/core/core.h>
#include <agar/core/config.h>

#include <agar/gui/gui.h>
#include <agar/gui/window.h>
#include <agar/gui/gui_math.h>
#include <agar/gui/text.h>
#include <agar/gui/cursors.h>

#include <ApplicationServices/ApplicationServices.h>
#include <Cocoa/Cocoa.h>
#include <OpenGL/CGLTypes.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/CGLRenderers.h>
#include <OpenGL/gl.h>

#include <agar/gui/drv_gl_common.h>
#include <agar/gui/drv_cocoa_keymap.h>

static int nDrivers = 0;		/* Drivers open */
static AG_DriverEventQ cocEventQ;	/* Private event queue */
static AG_EventSink   *cocEventSpinner = NULL;  /* Standard event sink */
static AG_EventSink   *cocEventEpilogue = NULL; /* Standard event epilogue */
struct ag_driver_cocoa;

/*
 * Application delegate
 */

@interface AG_AppDelegate : NSObject
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
@end

@implementation AG_AppDelegate : NSObject
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
{
	AG_QuitGUI();
	return (NSTerminateCancel);
}
@end

/*
 * Window interface
 */
@interface AG_CocoaWindow : NSWindow {
@public
	AG_Window *_agarWindow;		/* Corresponding Agar window */
}

- (BOOL)canBecomeKeyWindow;
- (BOOL)canBecomeMainWindow;
@end

@implementation AG_CocoaWindow
- (BOOL)canBecomeKeyWindow
{
	return (_agarWindow->flags & AG_WINDOW_DENYFOCUS) ? NO : YES;
}

- (BOOL)canBecomeMainWindow
{
	return (_agarWindow->flags & AG_WINDOW_MAIN) ? YES : NO;
}
@end

/*
 * View interface
 */
@interface AG_CocoaView : NSView {
@public
	AG_Window *_agarWindow;		/* Corresponding Agar window */
}
- (void)rightMouseDown:(NSEvent *)theEvent;
- (BOOL)preservesContentDuringLiveResize;
- (void)viewWillStartLiveResize;
- (void)viewDidEndLiveResize;
@end

@implementation AG_CocoaView
- (void)rightMouseDown:(NSEvent *)theEvent
{
	[[self nextResponder] rightMouseDown:theEvent];
}

- (BOOL)preservesContentDuringLiveResize
{
	return (YES);
}

- (void)viewWillStartLiveResize
{
	[super viewWillStartLiveResize];
}

- (void)viewDidEndLiveResize
{
	[super viewDidEndLiveResize];
}
@end

/*
 * Event listener interface
 */
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
@interface AG_CocoaListener : NSResponder <NSWindowDelegate> {
#else
@interface AG_CocoaListener : NSResponder {
#endif
	AG_Window *_window;
	struct ag_driver_cocoa *_driver;
}

-(void) listen:(struct ag_driver_cocoa *) driver;
-(void) close;

/* Window delegate functionality */
-(BOOL) windowShouldClose:(id) sender;
-(void) windowDidExpose:(NSNotification *) aNotification;
-(void) windowDidMove:(NSNotification *) aNotification;
-(void) windowDidResize:(NSNotification *) aNotification;
-(void) windowDidMiniaturize:(NSNotification *) aNotification;
-(void) windowDidDeminiaturize:(NSNotification *) aNotification;
-(void) windowDidBecomeKey:(NSNotification *) aNotification;
-(void) windowDidResignKey:(NSNotification *) aNotification;

@end

/* Driver instance data */
typedef struct ag_driver_cocoa {
	struct ag_driver_mw _inherit;
	AG_CocoaWindow   *win;		/* Cocoa window */
	AG_CocoaListener *evListener;	/* Cocoa event listener */
	NSOpenGLContext *glCtx;
	AG_GL_Context    gl;
	AG_Mutex         lock;		/* Protect Cocoa calls */
	Uint             modFlags;	/* Last modifier state */
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
	NSTrackingArea  *trackArea;	/* For mouse motion events */
#endif
} AG_DriverCocoa;

AG_DriverMwClass agDriverCocoa;

#define AGDRIVER_IS_COCOA(drv) \
	(AGDRIVER_CLASS(drv) == (AG_DriverClass *)&agDriverCocoa)

static int  COCOA_PendingEvents(void *);
static int  COCOA_GetNextEvent(void *, AG_DriverEvent *);
static int  COCOA_ProcessEvent(void *, AG_DriverEvent *);
static void COCOA_PostResizeCallback(AG_Window *, AG_SizeAlloc *);
static void COCOA_PostMoveCallback(AG_Window *, AG_SizeAlloc *);
static int  COCOA_RaiseWindow(AG_Window *);
static int  COCOA_SetInputFocus(AG_Window *);
#if 0
static void COCOA_FreeWidgetResources(AG_Widget *);
#endif

static __inline__ void
ConvertNSRect(NSRect *r)
{
	r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) -
	              r->origin.y - r->size.height;
}

@implementation AG_CocoaListener

- (void) listen:(AG_DriverCocoa *)co
{
	NSNotificationCenter *nc;
	NSWindow *win = co->win;
	NSView *view = [win contentView];

	_driver = co;
	_window = AGDRIVER_MW(co)->win;

	nc = [NSNotificationCenter defaultCenter];

	if ([win delegate] != nil) {
		[nc addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:win];
		[nc addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:win];
		[nc addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:win];
		[nc addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:win];
		[nc addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:win];
		[nc addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:win];
		[nc addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:win];
	} else {
		[win setDelegate:self];
	}

	[win setNextResponder:self];
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
	[win setAcceptsMouseMovedEvents:YES];
#endif
	[view setNextResponder:self];

#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
	if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)])
		[view setAcceptsTouchEvents:YES];
#endif
}

- (void)close
{
	NSNotificationCenter *nc;
	AG_DriverCocoa *co = _driver;
	NSWindow *win = co->win;
	NSView *view = [win contentView];

	nc = [NSNotificationCenter defaultCenter];

	if ([win delegate] != self) {
		[nc removeObserver:self name:NSWindowDidExposeNotification object:win];
		[nc removeObserver:self name:NSWindowDidMoveNotification object:win];
		[nc removeObserver:self name:NSWindowDidResizeNotification object:win];
		[nc removeObserver:self name:NSWindowDidMiniaturizeNotification object:win];
		[nc removeObserver:self name:NSWindowDidDeminiaturizeNotification object:win];
		[nc removeObserver:self name:NSWindowDidBecomeKeyNotification object:win];
		[nc removeObserver:self name:NSWindowDidResignKeyNotification object:win];
	} else {
		[win setDelegate:nil];
	}

	if ([win nextResponder] == self) {
		[win setNextResponder:nil];
	}
	if ([view nextResponder] == self) {
		[view setNextResponder:nil];
	}
}

- (BOOL)windowShouldClose:(id)sender
{
	AG_DriverEvent *dev;

	if ((dev = TryMalloc(sizeof(AG_DriverEvent))) != NULL) {
		dev->type = AG_DRIVER_CLOSE;
		dev->win = _window;
		TAILQ_INSERT_TAIL(&cocEventQ, dev, events);
	}
	return NO;
}

- (void)windowDidExpose:(NSNotification *)aNotification
{
	AG_DriverEvent *dev;

	if ((dev = TryMalloc(sizeof(AG_DriverEvent))) != NULL) {
		dev->type = AG_DRIVER_EXPOSE;
		dev->win = _window;
		TAILQ_INSERT_TAIL(&cocEventQ, dev, events);
	}
}

- (void)windowDidMove:(NSNotification *)aNotification
{
	AG_DriverCocoa *co = _driver;
	AG_Window *win = _window;
	NSRect rect;
	AG_SizeAlloc a;

	rect = [co->win contentRectForFrameRect:[co->win frame]];
	ConvertNSRect(&rect);

	a.x = (int)rect.origin.x;
	a.y = (int)rect.origin.y;
	a.w = WIDGET(win)->w;
	a.h = WIDGET(win)->h;
	COCOA_PostMoveCallback(win, &a);
}

- (void)windowDidResize:(NSNotification *)aNotification
{
	AG_Window *win = _window;
	AG_DriverCocoa *co = _driver;
	AG_SizeAlloc a;
	NSRect rect;

	rect = [co->win contentRectForFrameRect:[co->win frame]];
	ConvertNSRect(&rect);

	/*
	 * Since the event loop will not run during a live resize
	 * operation, we can't use AG_DRIVER_VIDEORESIZE, and we
	 * must redraw the window immediately.
	 */
	a.x = (int)rect.origin.x;
	a.y = (int)rect.origin.y;
	a.w = (int)rect.size.width;
	a.h = (int)rect.size.height;

	AG_MutexLock(&co->lock);
	AG_ObjectLock(win);

	if (a.w != WIDTH(win) || a.h != HEIGHT(win)) {
		COCOA_PostResizeCallback(win, &a);
	} else {
		COCOA_PostMoveCallback(win, &a);
	}
	if (win->visible) {
		AG_BeginRendering(_driver);
		AG_WindowDraw(win);
		AG_EndRendering(_driver);
	}

	AG_ObjectUnlock(win);
	AG_MutexUnlock(&co->lock);
}

- (void)windowDidMiniaturize:(NSNotification *)aNotification
{
	_window->flags |= AG_WINDOW_MINIMIZED;
}

- (void)windowDidDeminiaturize:(NSNotification *)aNotification
{
	_window->flags &= ~(AG_WINDOW_MINIMIZED);
}

- (void)windowDidBecomeKey:(NSNotification *)aNotification
{
	AG_DriverEvent *dev;

	agWindowFocused = _window;

	if ((dev = TryMalloc(sizeof(AG_DriverEvent))) != NULL) {
		dev->type = AG_DRIVER_FOCUS_IN;
		dev->win = _window;
		TAILQ_INSERT_TAIL(&cocEventQ, dev, events);
	}
}

- (void)windowDidResignKey:(NSNotification *)aNotification
{
	AG_DriverEvent *dev;

	if (agWindowFocused != _window) {
		return;
	}
	agWindowFocused = NULL;

	if ((dev = TryMalloc(sizeof(AG_DriverEvent))) != NULL) {
		dev->type = AG_DRIVER_FOCUS_OUT;
		dev->win = _window;
		TAILQ_INSERT_TAIL(&cocEventQ, dev, events);
	}
}

@end

static void
Init(void *obj)
{
	AG_DriverCocoa *co = obj;

	co->win = NULL;
	co->glCtx = NULL;
	co->modFlags = 0;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
	co->trackArea = nil;
#endif
	AG_MutexInitRecursive(&co->lock);
}

static void
Destroy(void *obj)
{
	AG_DriverCocoa *co = obj;

	AG_MutexDestroy(&co->lock);
}

/*
 * Standard AG_EventLoop() event sink.
 */
static int
COCOA_EventSink(AG_EventSink *es, AG_Event *event)
{
	AG_DriverEvent dev;

	if (COCOA_GetNextEvent(NULL, &dev) == 1) {
		return COCOA_ProcessEvent(NULL, &dev);
	}
	return (0);
}
static int
COCOA_EventEpilogue(AG_EventSink *es, AG_Event *event)
{
	AG_WindowDrawQueued();
	AG_WindowProcessQueued();
	return (0);
}

static int
COCOA_Open(void *obj, const char *spec)
{
	AG_Driver *drv = obj;
	AG_DriverCocoa *co = obj;
	NSAutoreleasePool *pool;

	/* Driver manages rendering of window background. */
	drv->flags |= AG_DRIVER_WINDOW_BG;

	/* Initialize NSApp if needed. */
	pool = [[NSAutoreleasePool alloc] init];
	if (NSApp == nil) {
		NSApp = [NSApplication sharedApplication];
		[NSApp finishLaunching];
	}
	if ([NSApp delegate] == nil) {
		[NSApp setDelegate:[[AG_AppDelegate alloc] init]];
	}
	[pool release];

	/* Initialize the core mouse and keyboard */
	/* TODO: touch handling */
	if ((drv->mouse = AG_MouseNew(co, "X mouse")) == NULL ||
	    (drv->kbd = AG_KeyboardNew(co, "X keyboard")) == NULL) {
		goto fail;
	}
	if (nDrivers == 0) {
		TAILQ_INIT(&cocEventQ);

		/* Set up event filters for standard AG_EventLoop(). */
		if ((cocEventSpinner = AG_AddEventSpinner(COCOA_EventSink, NULL)) == NULL ||
		    (cocEventEpilogue = AG_AddEventEpilogue(COCOA_EventEpilogue, NULL)) == NULL)
			goto fail;
	}
	nDrivers++;
	return (0);
fail:
	if (cocEventSpinner != NULL) { AG_DelEventSpinner(cocEventSpinner); cocEventSpinner = NULL; }
	if (cocEventEpilogue != NULL) { AG_DelEventEpilogue(cocEventEpilogue); cocEventEpilogue = NULL; }
	if (drv->kbd != NULL) { AG_ObjectDelete(drv->kbd); drv->kbd = NULL; }
	if (drv->mouse != NULL) { AG_ObjectDelete(drv->mouse); drv->mouse = NULL; }
	return (-1);
}

static void
COCOA_Close(void *obj)
{
	AG_Driver *drv = obj;

#ifdef AG_DEBUG
	if (nDrivers == 0) { AG_FatalError("Driver close without open"); }
#endif
	if (--nDrivers == 0) {
		AG_DriverEvent *dev, *devNext;

		AG_DelEventSink(cocEventSpinner); cocEventSpinner = NULL;
		AG_DelEventEpilogue(cocEventEpilogue); cocEventEpilogue = NULL;

		for (dev = TAILQ_FIRST(&cocEventQ);
		     dev != TAILQ_LAST(&cocEventQ, ag_driver_eventq);
		     dev = devNext) {
			devNext = TAILQ_NEXT(dev, events);
			Free(dev);
		}
		TAILQ_INIT(&cocEventQ);
	}

	AG_ObjectDelete(drv->mouse); drv->mouse = NULL;
	AG_ObjectDelete(drv->kbd); drv->kbd = NULL;
}

static int
COCOA_GetDisplaySize(Uint *w, Uint *h)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	NSScreen *screen;
	NSRect sr;

	/* XXX this is probably wrong */
	screen = [NSScreen mainScreen];
	sr = [screen frame];
	*w = sr.size.width;
	*h = sr.size.height;
	[pool release];
	return (0);
}

static int
COCOA_PendingEvents(void *drvCaller)
{
	NSAutoreleasePool *pool;
	NSEvent *ev;
	int rv;

	if (!TAILQ_EMPTY(&cocEventQ))
		return (1);

	pool = [[NSAutoreleasePool alloc] init];
	ev = [NSApp nextEventMatchingMask:NSAnyEventMask
	                                  untilDate:[NSDate distantPast]
					  inMode:NSDefaultRunLoopMode
					  dequeue:NO];
	rv = (ev != nil);

	[pool release];
	return (rv);
}

/* Convert a NSEvent mouse button number to AG_MouseButton. */
static AG_MouseButton
GetMouseButton(int which)
{
	switch (which) {
	case 0:		return (AG_MOUSE_LEFT);
	case 1:		return (AG_MOUSE_RIGHT);
	case 2:		return (AG_MOUSE_MIDDLE);
	default:	return (which+1);
	}
}

static AG_MouseButton
GetScrollWheelButton(float x, float y)
{
	if (x > 0) {
		return (AG_MOUSE_X1);
	} else if (x < 0) {
		return (AG_MOUSE_X2);
	}
	if (y > 0) {
		return (AG_MOUSE_WHEELUP);
	} else if (y < 0) {
		return (AG_MOUSE_WHEELDOWN);
	}
	return (AG_MOUSE_NONE);
}

/* Add a keyboard event to the queue. */
static void
QueueKeyEvent(AG_DriverCocoa *co, enum ag_driver_event_type type,
    AG_KeySym ks, Uint32 ucs)
{
	AG_DriverEvent *dev;

	if ((dev = TryMalloc(sizeof(AG_DriverEvent))) == NULL) {
		AG_Verbose("Out of memory for keymod event\n");
		return;
	}
	dev->type = type;
	dev->win = AGDRIVER_MW(co)->win;
	dev->data.key.ks = ks;
	dev->data.key.ucs = ucs;
	TAILQ_INSERT_TAIL(&cocEventQ, dev, events);
}

static int
COCOA_GetNextEvent(void *drvCaller, AG_DriverEvent *dev)
{
	NSAutoreleasePool *pool;
	AG_CocoaWindow *coWin;
	AG_Window *win;
	AG_Driver *drv;
	AG_DriverCocoa *co;
	AG_DriverEvent *devFirst;
	NSEvent *event;
	int rv = 0;

	if (!TAILQ_EMPTY(&cocEventQ))
		goto out_dequeue;

	pool = [[NSAutoreleasePool alloc] init];
	event = [NSApp nextEventMatchingMask:NSAnyEventMask
	         untilDate:[NSDate distantPast]
	         inMode:NSDefaultRunLoopMode
	         dequeue:YES];

	if (event == nil) {
		goto out;
	}

	if ((coWin = (AG_CocoaWindow *)[event window]) == nil) {
		[NSApp sendEvent:event];
		goto out;
	}
	win = coWin->_agarWindow;

	AG_LockVFS(&agDrivers);
	drv = WIDGET(win)->drv;
	co = (AG_DriverCocoa *)drv;

	switch ([event type]) {
	case NSMouseMoved:
	case NSLeftMouseDragged:
	case NSRightMouseDragged:
	case NSOtherMouseDragged:
		{
			NSPoint point = [event locationInWindow];
			int x = (int)point.x;
			int y = (int)(WIDGET(win)->h - point.y);

			AG_MouseMotionUpdate(drv->mouse, x, y);
			dev->type = AG_DRIVER_MOUSE_MOTION;
			dev->win = win;
			dev->data.motion.x = x;
			dev->data.motion.y = y;
			rv = 1;
			break;
		}
	case NSScrollWheel:
		{
			float x = [event deltaX];
			float y = [event deltaY];
			AG_MouseButton btn = GetScrollWheelButton(x, y);

			if (btn == AG_MOUSE_NONE) {
				break;
			}
			AG_MouseButtonUpdate(drv->mouse, AG_BUTTON_PRESSED, btn);
			dev->type = AG_DRIVER_MOUSE_BUTTON_DOWN;
			dev->win = win;
			dev->data.button.which = btn;
			dev->data.button.x = drv->mouse->x;
			dev->data.button.y = drv->mouse->y;
			rv = 1;
			break;
		}
	case NSLeftMouseDown:
	case NSOtherMouseDown:
	case NSRightMouseDown:
		{
			AG_MouseButton btn = GetMouseButton([event buttonNumber]);

			AG_MouseButtonUpdate(drv->mouse, AG_BUTTON_PRESSED, btn);
			dev->type = AG_DRIVER_MOUSE_BUTTON_DOWN;
			dev->win = win;
			dev->data.button.which = btn;
			dev->data.button.x = drv->mouse->x;
			dev->data.button.y = drv->mouse->y;
			rv = 1;
			break;
		}
	case NSLeftMouseUp:
	case NSOtherMouseUp:
	case NSRightMouseUp:
		{
			AG_MouseButton btn = GetMouseButton([event buttonNumber]);

			AG_MouseButtonUpdate(drv->mouse, AG_BUTTON_RELEASED, btn);
			dev->type = AG_DRIVER_MOUSE_BUTTON_UP;
			dev->win = win;
			dev->data.button.which = btn;
			dev->data.button.x = drv->mouse->x;
			dev->data.button.y = drv->mouse->y;
			rv = 1;
			break;
		}
	case NSMouseEntered:
		if ([co->win isKeyWindow]) {
			dev->type = AG_DRIVER_MOUSE_ENTER;
			dev->win = win;
			rv = 1;
		} else {
			rv = 0;
		}
		break;
	case NSMouseExited:
		if ([co->win isKeyWindow]) {
			dev->type = AG_DRIVER_MOUSE_LEAVE;
			dev->win = win;
			rv = 1;
		} else {
			rv = 0;
		}
		break;
	case NSKeyDown:
		if ([event isARepeat]) {
			/* Agar implements its own key repeat */
			goto out;
		}
		/* FALLTHROUGH */
	case NSKeyUp:
		{
			NSString *characters = [event characters];
			enum ag_driver_event_type evType;
			enum ag_keyboard_action kbdAction;
			AG_KeySym ks;
			unichar c;
			NSUInteger i;

			if ([characters length] == 0)
				goto out;

			if ([event type] == NSKeyDown) {
				evType = AG_DRIVER_KEY_DOWN;
				kbdAction = AG_KEY_PRESSED;
			} else {
				evType = AG_DRIVER_KEY_UP;
				kbdAction = AG_KEY_RELEASED;
			}

			/* Look for matching function keys first. */
			c = [characters characterAtIndex: 0];
			ks = AG_KEY_NONE;
			for (i = 0; i < agCocoaFunctionKeysSize; i++) {
				const struct ag_cocoa_function_key *fnKey =
				    &agCocoaFunctionKeys[i];

				if (fnKey->uc == c) {
					ks = fnKey->keySym;
					break;
				}
			}
			if (ks != AG_KEY_NONE) {
				AG_KeyboardUpdate(drv->kbd, kbdAction, ks, 0);
				dev->type = evType;
				dev->win = win;
				dev->data.key.ks = ks;
				if (ks == AG_KEY_RETURN) {
					dev->data.key.ucs = '\n';
				} else {
					dev->data.key.ucs = 0;
				}
				rv = 1;
				goto out;
			}

			/* Process as a character sequence. */
			for (i = 0; i < [characters length]; i++) {
				AG_KeySym ks;

				c = [characters characterAtIndex: i];
				ks = (c <= AG_KEY_ASCII_END) ?
				    (AG_KeySym)c : AG_KEY_NONE;
				AG_KeyboardUpdate(drv->kbd, kbdAction, ks,
				    (Uint32)c);

				if (i == 0) {
					dev->type = evType;
					dev->win = win;
					dev->data.key.ks = ks;
					dev->data.key.ucs = (Uint32)c;
					rv = 1;
				} else {
					QueueKeyEvent(co, evType, ks,
					    (Uint32)c);
				}
			}
			if (rv == 1)
				goto out;
		}
	case NSFlagsChanged:
		{
			Uint modFlags = [event modifierFlags];
			int i, nChanged = 0;

			for (i = 0; i < agCocoaKeymodSize; i++) {
				const struct ag_cocoa_keymod_entry *kmEnt =
				    &agCocoaKeymod[i];

				if ((modFlags & kmEnt->keyMask) &&
				     !(co->modFlags & kmEnt->keyMask)) {
					AG_KeyboardUpdate(drv->kbd, AG_KEY_PRESSED, kmEnt->keySym, 0);
					QueueKeyEvent(co, AG_DRIVER_KEY_DOWN, kmEnt->keySym, 0);
					nChanged++;
				} else if (!(modFlags & kmEnt->keyMask) &&
				    (co->modFlags & kmEnt->keyMask)) {
					AG_KeyboardUpdate(drv->kbd, AG_KEY_RELEASED, kmEnt->keySym, 0);
					QueueKeyEvent(co, AG_DRIVER_KEY_UP, kmEnt->keySym, 0);
					nChanged++;
				}
			}
			co->modFlags = modFlags;

			if (nChanged > 0) {
				goto out_dequeue;
			}
			break;
		}
	default:
		break;
	}
	[NSApp sendEvent:event];
out:
	[pool release];
	return (rv);
out_dequeue:
	devFirst = TAILQ_FIRST(&cocEventQ);
	TAILQ_REMOVE(&cocEventQ, devFirst, events);
	memcpy(dev, devFirst, sizeof(AG_DriverEvent));
	Free(devFirst);
	return (1);
}

static int
COCOA_ProcessEvent(void *drvCaller, AG_DriverEvent *dev)
{
	AG_Driver *drv;
	int rv = 1;

	if (dev->win == NULL ||
	    dev->win->flags & AG_WINDOW_DETACHING)
		return (0);

	AG_LockVFS(&agDrivers);
	drv = WIDGET(dev->win)->drv;

	switch (dev->type) {
	case AG_DRIVER_MOUSE_MOTION:
		AG_ProcessMouseMotion(dev->win,
		    dev->data.motion.x, dev->data.motion.y,
		    drv->mouse->xRel, drv->mouse->yRel,
		    drv->mouse->btnState);
		AG_MouseCursorUpdate(dev->win,
		     dev->data.motion.x, dev->data.motion.y);
		break;
	case AG_DRIVER_MOUSE_BUTTON_DOWN:
		AG_ProcessMouseButtonDown(dev->win,
		    dev->data.button.x, dev->data.button.y,
		    dev->data.button.which);
		break;
	case AG_DRIVER_MOUSE_BUTTON_UP:
		AG_ProcessMouseButtonUp(dev->win,
		    dev->data.button.x, dev->data.button.y,
		    dev->data.button.which);
		break;
	case AG_DRIVER_KEY_UP:
		AG_ProcessKey(drv->kbd, dev->win, AG_KEY_RELEASED,
		    dev->data.key.ks, dev->data.key.ucs);
		break;
	case AG_DRIVER_KEY_DOWN:
		AG_ProcessKey(drv->kbd, dev->win, AG_KEY_PRESSED,
		    dev->data.key.ks, dev->data.key.ucs);
		break;
	case AG_DRIVER_MOUSE_ENTER:
		AG_PostEvent(NULL, dev->win, "window-enter", NULL);
		break;
	case AG_DRIVER_MOUSE_LEAVE:
		AG_PostEvent(NULL, dev->win, "window-leave", NULL);
		break;
	case AG_DRIVER_FOCUS_IN:
		agWindowFocused = dev->win;
		AG_PostEvent(NULL, dev->win, "window-gainfocus", NULL);
		break;
	case AG_DRIVER_FOCUS_OUT:
		AG_PostEvent(NULL, dev->win, "window-lostfocus", NULL);
		break;
	case AG_DRIVER_CLOSE:
		AG_PostEvent(NULL, dev->win, "window-close", NULL);
		break;
	case AG_DRIVER_EXPOSE:
		dev->win->dirty = 1;
		break;
	default:
		rv = 0;
		break;
	}
	AG_UnlockVFS(&agDrivers);
	return (rv);
}

/* Select the window's OpenGL context. */
static __inline__ void
COCOA_GL_MakeCurrent(AG_DriverCocoa *co, AG_Window *win)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

	[co->glCtx setView:[co->win contentView]];
	[co->glCtx update];
	[co->glCtx makeCurrentContext];

	[pool release];
}

static void
COCOA_BeginRendering(void *obj)
{
	AG_DriverCocoa *co = obj;

	AG_MutexLock(&co->lock);
	COCOA_GL_MakeCurrent(co, AGDRIVER_MW(co)->win);
}

static void
COCOA_RenderWindow(AG_Window *win)
{
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;
	AG_GL_Context *gl = &co->gl;
	AG_Color c = WCOLOR(win,0);

	gl->clipStates[0] = glIsEnabled(GL_CLIP_PLANE0); glEnable(GL_CLIP_PLANE0);
	gl->clipStates[1] = glIsEnabled(GL_CLIP_PLANE1); glEnable(GL_CLIP_PLANE1);
	gl->clipStates[2] = glIsEnabled(GL_CLIP_PLANE2); glEnable(GL_CLIP_PLANE2);
	gl->clipStates[3] = glIsEnabled(GL_CLIP_PLANE3); glEnable(GL_CLIP_PLANE3);

	glClearColor(c.r/255.0,
	             c.g/255.0,
		     c.b/255.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	AG_WidgetDraw(win);
}

static void
COCOA_EndRendering(void *obj)
{
	AG_DriverCocoa *co = obj;
	AG_GL_Context *gl = &co->gl;
	Uint i;

	[co->glCtx flushBuffer];

	/* Remove textures and display lists queued for deletion. */
	glDeleteTextures(gl->nTextureGC, (const GLuint *)gl->textureGC);
	for (i = 0; i < gl->nListGC; i++) {
		glDeleteLists(gl->listGC[i], 1);
	}
	gl->nTextureGC = 0;
	gl->nListGC = 0;
	AG_MutexUnlock(&co->lock);
}

/*
 * Window operations
 */

static void
SetBackgroundColor(AG_DriverCocoa *co, AG_Color C)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	NSColor *bgColor;
	CGFloat r, g, b, a;

	r = (CGFloat)(C.r / 255.0);
	g = (CGFloat)(C.g / 255.0);
	b = (CGFloat)(C.b / 255.0);
	a = (CGFloat)(C.a / 255.0);
	bgColor = [NSColor colorWithCalibratedRed:r green:g blue:b alpha:a];
	[co->win setBackgroundColor:bgColor];

	[pool release];
}

static int
COCOA_OpenWindow(AG_Window *win, AG_Rect r, int depthReq, Uint mwFlags)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;
	AG_Driver *drv = WIDGET(win)->drv;
	Uint winStyle = 0;
	NSRect winRect, scrRect;
	NSArray *screens;
	NSScreen *screen, *selScreen = nil;
	AG_CocoaView *contentView;
	NSOpenGLPixelFormatAttribute pfAttr[32];
	NSOpenGLPixelFormat *pf;
	int i, count;
	AG_SizeAlloc a;

	AG_MutexLock(&co->lock);

	/* Set the window style. */
	if (win->flags & AG_WINDOW_NOBORDERS) {
		winStyle = NSBorderlessWindowMask;
	} else {
		if (!(win->flags & AG_WINDOW_NOTITLE)) { winStyle |= NSTitledWindowMask; }
		if (!(win->flags & AG_WINDOW_NOCLOSE)) { winStyle |= NSClosableWindowMask; }
		if (!(win->flags & AG_WINDOW_NOMINIMIZE)) { winStyle |= NSMiniaturizableWindowMask; }
		if (!(win->flags & AG_WINDOW_NORESIZE)) { winStyle |= NSResizableWindowMask; }
	}

	/* Set the window coordinates. */
	winRect.origin.x = r.x;
	winRect.origin.y = r.y;
	winRect.size.width = r.w;
	winRect.size.height = r.h;
	ConvertNSRect(&winRect);

	/* Select a screen. */
	screens = [NSScreen screens];
	count = [screens count];
	for (i = 0; i < count; i++) {
		screen = [screens objectAtIndex:i];
		scrRect = [screen frame];

		if (winRect.origin.x >= scrRect.origin.x &&
		    winRect.origin.y >= scrRect.origin.y &&
		    winRect.origin.x < scrRect.origin.x + scrRect.size.width &&
		    winRect.origin.y < scrRect.origin.y + scrRect.size.height) {
		    	selScreen = screen;
			winRect.origin.x -= scrRect.origin.x;
			winRect.origin.y -= scrRect.origin.y;
			break;
		}
	}

	/* Create the window. */
	if (selScreen == nil) {
		co->win = [[AG_CocoaWindow alloc] initWithContentRect:winRect
		                                  styleMask:winStyle
					          backing:NSBackingStoreBuffered
					          defer:YES];
	} else {
		co->win = [[AG_CocoaWindow alloc] initWithContentRect:winRect
		                                  styleMask:winStyle
					          backing:NSBackingStoreBuffered
					          defer:YES
					          screen:selScreen];
	}
	co->win->_agarWindow = win;
	SetBackgroundColor(co, WCOLOR(win,0));

	if (win->flags & AG_WINDOW_MAIN)
		[co->win makeMainWindow];

	/* Create an event listener. */
	co->evListener = [[AG_CocoaListener alloc] init];

	/* Obtain the effective window coordinates; set up our contentView. */
	winRect = [co->win contentRectForFrameRect:[co->win frame]];
	contentView = [[AG_CocoaView alloc] initWithFrame:winRect];
	contentView->_agarWindow = win;
	[co->win setContentView: contentView];
	[contentView release];

	/* Set our event listener. */
	[co->evListener listen:co];

	/* Retrieve the effective style flags. */
	winStyle = [co->win styleMask];
	if (winStyle == NSBorderlessWindowMask) {
		win->flags |= AG_WINDOW_NOBORDERS;
	} else {
		if (!(winStyle & NSTitledWindowMask)) { win->flags |= AG_WINDOW_NOTITLE; }
		if (!(winStyle & NSClosableWindowMask)) { win->flags |= AG_WINDOW_NOCLOSE; }
		if (!(winStyle & NSMiniaturizableWindowMask)) { win->flags |= AG_WINDOW_NOMINIMIZE; }
		if (!(winStyle & NSResizableWindowMask)) { win->flags |= AG_WINDOW_NORESIZE; }
	}

	/* Retrieve the effective maximize/minimize and focus state. */
	if (!(win->flags & AG_WINDOW_NORESIZE) && [co->win isZoomed]) {
		win->flags |= AG_WINDOW_MAXIMIZED;
	} else {
		win->flags &= ~(AG_WINDOW_MAXIMIZED);
	}
	if ([co->win isMiniaturized]) {
		win->flags |= AG_WINDOW_MINIMIZED;
	} else {
		win->flags &= ~(AG_WINDOW_MINIMIZED);
	}
	if ([co->win isKeyWindow])
		agWindowFocused = win;

	/* Create an OpenGL rendering context. */
	i = 0;
	if (depthReq != 0) {
		pfAttr[i++] = NSOpenGLPFADepthSize;
		pfAttr[i++] = depthReq;
	}
	pfAttr[i++] = NSOpenGLPFADoubleBuffer;
	if (agStereo) { pfAttr[i++] = NSOpenGLPFAStereo; }
	pfAttr[i] = 0;
	pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:pfAttr];
	if (pf == nil) {
		AG_SetError("Cannot create NSOpenGLPixelFormat");
		goto fail;
	}
	co->glCtx = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil];
	[pf release];
	if (co->glCtx == nil) {
		AG_SetError("Cannot create NSOpenGLContext");
		goto fail;
	}
	[co->glCtx update];
	[co->glCtx makeCurrentContext];
	if (AG_GL_InitContext(co, &co->gl) == -1)
		goto fail;

	/* Set the preferred Agar pixel formats. */
	/* XXX XXX XXX: retrieve effective depth */
	drv->videoFmt = AG_PixelFormatRGB(depthReq != 0 ? depthReq : 16,
#if AG_BYTEORDER == AG_BIG_ENDIAN
		0xff000000, 0x00ff0000, 0x0000ff00
#else
		0x000000ff, 0x0000ff00, 0x00ff0000
#endif
	);
	if (drv->videoFmt == NULL)
		goto fail_ctx;

	/*
	 * Set the effective window geometry, initialize the viewport
	 * and tracking rectangle.
	 */
	ConvertNSRect(&winRect);
	a.x = winRect.origin.x;
	a.y = winRect.origin.y;
	a.w = winRect.size.width;
	a.h = winRect.size.height;
	COCOA_PostResizeCallback(win, &a);

	AG_MutexUnlock(&co->lock);
	[pool release];
	return (0);
fail_ctx:
	AG_GL_DestroyContext(co);
fail:
	[NSOpenGLContext clearCurrentContext];
	[co->evListener close];
	[co->evListener release];
	[co->win close];
	if (drv->videoFmt) {
		AG_PixelFormatFree(drv->videoFmt);
		drv->videoFmt = NULL;
	}
	AG_MutexUnlock(&co->lock);
	[pool release];
	return (-1);
}

static void
COCOA_CloseWindow(AG_Window *win)
{
	AG_Driver *drv = WIDGET(win)->drv;
	AG_DriverCocoa *co = (AG_DriverCocoa *)drv;
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

	AG_MutexLock(&co->lock);

#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
	if (co->trackArea != nil) {
		[[co->win contentView] removeTrackingArea:co->trackArea];
		[co->trackArea release];
		co->trackArea = nil;
	}
#endif
	/* Destroy our OpenGL rendering context. */
	COCOA_GL_MakeCurrent(co, win);
	AG_GL_DestroyContext(drv);
	[co->glCtx clearDrawable];
	[co->glCtx release];

	/* Close the window. */
	[co->evListener close];
	[co->evListener release];
	[co->win close];

	AG_PixelFormatFree(drv->videoFmt);
	drv->videoFmt = NULL;

	AG_MutexUnlock(&co->lock);
	[pool release];
}

static int
COCOA_MapWindow(AG_Window *win)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;

	AG_MutexLock(&co->lock);
	if (![co->win isMiniaturized]) {
		[co->win makeKeyAndOrderFront:nil];
	}
	AG_MutexUnlock(&co->lock);

	[pool release];
	return (0);
}

static int
COCOA_UnmapWindow(AG_Window *win)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;

	AG_MutexLock(&co->lock);
	[co->win orderOut:nil];
	AG_MutexUnlock(&co->lock);

	[pool release];
	return (0);
}

static int
COCOA_RaiseWindow(AG_Window *win)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;

	AG_MutexLock(&co->lock);
	[co->win makeKeyAndOrderFront:nil];
	AG_MutexUnlock(&co->lock);

	[pool release];
	return (0);
}

static int
COCOA_LowerWindow(AG_Window *win)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;

	AG_MutexLock(&co->lock);
	if (![co->win isMiniaturized]) {
		[co->win orderBack:nil];
	}
	AG_MutexUnlock(&co->lock);

	[pool release];
	return (0);
}

static int
COCOA_ReparentWindow(AG_Window *win, AG_Window *winParent, int x, int y)
{
	/* TODO */
	AG_SetError("Reparent window not implemented");
	return (-1);
}

static int
COCOA_GetInputFocus(AG_Window **rv)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = NULL;

	AGOBJECT_FOREACH_CHILD(co, &agDrivers, ag_driver_cocoa) {
		if (!AGDRIVER_IS_COCOA(co)) {
			continue;
		}
		AG_MutexLock(&co->lock);
		if ([co->win isKeyWindow]) {
			AG_MutexUnlock(&co->lock);
			break;
		}
		AG_MutexUnlock(&co->lock);
	}
	if (co == NULL) {
		AG_SetError("Input focus is external to this application");
		goto fail;
	}
	*rv = AGDRIVER_MW(co)->win;
	[pool release];
	return (0);
fail:
	[pool release];
	return (-1);
}

static int
COCOA_SetInputFocus(AG_Window *win)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;

	AG_MutexLock(&co->lock);
	/* XXX use makeKeyWindow? */
	[co->win makeKeyAndOrderFront:nil];
	AG_MutexUnlock(&co->lock);

	[pool release];
	return (0);
}

static void
COCOA_PreResizeCallback(AG_Window *win)
{
#if 0
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;

	/*
	 * Backup all GL resources since it is not portable to assume that a
	 * display resize will not cause a change in GL contexts
	 * (XXX TODO test for platforms where this is unnecessary)
	 * (XXX is this correctly done?)
	 */
	COCOA_GL_MakeCurrent(co, win);
	COCOA_FreeWidgetResources(WIDGET(win));
	AG_TextClearGlyphCache(co);
#endif
}

static void
COCOA_PostResizeCallback(AG_Window *win, AG_SizeAlloc *a)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_Driver *drv = WIDGET(win)->drv;
	AG_DriverCocoa *co = (AG_DriverCocoa *)drv;
	int x = a->x;
	int y = a->y;
	NSRect trackRect;

	AG_MutexLock(&co->lock);

	/* Update per-widget coordinate information. */
	a->x = 0;
	a->y = 0;
	(void)AG_WidgetSizeAlloc(win, a);
	AG_WidgetUpdateCoords(win, 0, 0);

	/* The viewport coordinates have changed. */
	[co->glCtx makeCurrentContext];
	AG_GL_SetViewport(&co->gl, AG_RECT(0, 0, WIDTH(win), HEIGHT(win)));

#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
	/* Update the tracking rectangle. */
	if (co->trackArea != nil) {
		[[co->win contentView] removeTrackingArea:co->trackArea];
		[co->trackArea release];
		co->trackArea = nil;
	}
	trackRect.origin.x = 0;
	trackRect.origin.y = 0;
	trackRect.size.width = WIDTH(win);
	trackRect.size.height = HEIGHT(win);
	co->trackArea = [[NSTrackingArea alloc] initWithRect:trackRect
	                 options: (NSTrackingMouseEnteredAndExited|
			           NSTrackingMouseMoved|
				   NSTrackingActiveAlways)
			 owner:co->win userInfo:nil];
	[[co->win contentView] addTrackingArea:co->trackArea];
#endif /* >= 10.5 */

	AG_MutexUnlock(&co->lock);

	/* Save the new effective window position. */
	WIDGET(win)->x = a->x = x;
	WIDGET(win)->y = a->y = y;

	[pool release];
}

static void
COCOA_PostMoveCallback(AG_Window *win, AG_SizeAlloc *a)
{
	AG_Driver *drv = WIDGET(win)->drv;
	AG_DriverCocoa *co = (AG_DriverCocoa *)drv;
	AG_SizeAlloc aNew;
	int xRel, yRel;

	AG_MutexLock(&co->lock);

	xRel = a->x - WIDGET(win)->x;
	yRel = a->y - WIDGET(win)->y;

	/* Update the window coordinates. */
	aNew.x = 0;
	aNew.y = 0;
	aNew.w = a->w;
	aNew.h = a->h;
	AG_WidgetSizeAlloc(win, &aNew);
	AG_WidgetUpdateCoords(win, 0, 0);
	WIDGET(win)->x = a->x;
	WIDGET(win)->y = a->y;
	win->dirty = 1;

	/* Move other windows pinned to this one. */
	AG_WindowMovePinned(win, xRel, yRel);

	AG_MutexUnlock(&co->lock);
}

static int
COCOA_MoveWindow(AG_Window *win, int x, int y)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;
	NSScreen *screen = [co->win screen];
	NSRect scrRect = [screen frame];
	NSPoint pt;

	pt.x = x;
	pt.y = scrRect.size.height - y;

	AG_MutexLock(&co->lock);
	[co->win setFrameTopLeftPoint:pt];
	AG_MutexUnlock(&co->lock);

	[pool release];
	return (0);
}

#if 0
/* Save/restore associated widget GL resources (for GL context changes). */
static void
COCOA_FreeWidgetResources(AG_Widget *wid)
{
	AG_Widget *chld;

	OBJECT_FOREACH_CHILD(chld, wid, ag_widget) {
		COCOA_FreeWidgetResources(chld);
	}
	AG_WidgetFreeResourcesGL(wid);
}
#endif

static int
COCOA_ResizeWindow(AG_Window *win, Uint w, Uint h)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;
	NSSize sz;

	sz.width = w;
	sz.height = h;

	AG_MutexLock(&co->lock);
	[co->win setContentSize:sz];
	AG_MutexUnlock(&co->lock);

	[pool release];
	return (0);
}

static int
COCOA_MoveResizeWindow(AG_Window *win, AG_SizeAlloc *a)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;
	NSScreen *screen = [co->win screen];
	NSRect scrRect = [screen frame];
	NSPoint pt;
	NSSize sz;

	pt.x = a->x;
	pt.y = scrRect.size.height - a->y;
	sz.width = a->w;
	sz.height = a->h;

	AG_MutexLock(&co->lock);
	[co->win setFrameTopLeftPoint:pt];
	[co->win setContentSize:sz];
	AG_MutexUnlock(&co->lock);

	[pool release];
	return (0);
}

static int
COCOA_SetBorderWidth(AG_Window *win, Uint width)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;

	AG_MutexLock(&co->lock);
	if (([co->win styleMask] & NSTexturedBackgroundWindowMask) == 0) {
		[co->win setContentBorderThickness:width forEdge:NSMaxYEdge];
	}
	[co->win setContentBorderThickness:width forEdge:NSMinYEdge];
	AG_MutexUnlock(&co->lock);

	[pool release];
	return (0);
}

static int
COCOA_SetWindowCaption(AG_Window *win, const char *s)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;
	NSString *string;

	if (win->caption[0] != '\0') {
		string = [[NSString alloc] initWithUTF8String:win->caption];
	} else {
		string = [[NSString alloc] init];
	}

	AG_MutexLock(&co->lock);
	[co->win setTitle:string];
	AG_MutexUnlock(&co->lock);

	[string release];
	[pool release];
	return (0);
}

static int
COCOA_SetOpacity(AG_Window *win, float f)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	AG_DriverCocoa *co = (AG_DriverCocoa *)WIDGET(win)->drv;

	AG_MutexLock(&co->lock);
	if (f > 0.99) {
		[co->win setOpaque:YES];
		[co->win setAlphaValue:1.0];
	} else {
		[co->win setOpaque:NO];
		[co->win setAlphaValue:f];
	}
	AG_MutexUnlock(&co->lock);

	[pool release];
	return (0);
}

static void
COCOA_TweakAlignment(AG_Window *win, AG_SizeAlloc *a, Uint wMax, Uint hMax)
{
	/* XXX TODO */
	switch (win->alignment) {
	case AG_WINDOW_TL:
	case AG_WINDOW_TC:
	case AG_WINDOW_TR:
		a->y += 50;
		if (a->y+a->h > hMax) { a->y = 0; }
		break;
	case AG_WINDOW_BL:
	case AG_WINDOW_BC:
	case AG_WINDOW_BR:
		a->y -= 100;
		if (a->y < 0) { a->y = 0; }
		break;
	default:
		break;
	}
}

AG_DriverMwClass agDriverCocoa = {
	{
		{
			"AG_Driver:AG_DriverMw:AG_DriverCocoa",
			sizeof(AG_DriverCocoa),
			{ 1,5 },
			Init,
			NULL,	/* reinit */
			Destroy,
			NULL,	/* load */
			NULL,	/* save */
			NULL,	/* edit */
		},
		"cocoa",
		AG_VECTOR,
		AG_WM_MULTIPLE,
		AG_DRIVER_OPENGL|AG_DRIVER_TEXTURES,
		COCOA_Open,
		COCOA_Close,
		COCOA_GetDisplaySize,
		NULL,			/* beginEventProcessing */
		COCOA_PendingEvents,
		COCOA_GetNextEvent,
		COCOA_ProcessEvent,
		NULL,			/* genericEventLoop */
		NULL,			/* endEventProcessing */
		NULL,			/* terminate */
		COCOA_BeginRendering,
		COCOA_RenderWindow,
		COCOA_EndRendering,
		AG_GL_FillRect,
		NULL,			/* updateRegion */
		AG_GL_StdUploadTexture,
		AG_GL_StdUpdateTexture,
		AG_GL_StdDeleteTexture,
		NULL,			/* setRefreshRate */
		AG_GL_StdPushClipRect,
		AG_GL_StdPopClipRect,
		AG_GL_StdPushBlendingMode,
		AG_GL_StdPopBlendingMode,
		NULL,			/* createCursor */
		NULL,			/* freeCursor */
		NULL,			/* setCursor */
		NULL,			/* unsetCursor */
		NULL,			/* getCursorVisibility */
		NULL,			/* setCursorVisibility */
		AG_GL_BlitSurface,
		AG_GL_BlitSurfaceFrom,
		AG_GL_BlitSurfaceGL,
		AG_GL_BlitSurfaceFromGL,
		AG_GL_BlitSurfaceFlippedGL,
		AG_GL_BackupSurfaces,
		AG_GL_RestoreSurfaces,
		AG_GL_RenderToSurface,
		AG_GL_PutPixel,
		AG_GL_PutPixel32,
		AG_GL_PutPixelRGB,
		AG_GL_BlendPixel,
		AG_GL_DrawLine,
		AG_GL_DrawLineH,
		AG_GL_DrawLineV,
		AG_GL_DrawLineBlended,
		AG_GL_DrawArrowUp,
		AG_GL_DrawArrowDown,
		AG_GL_DrawArrowLeft,
		AG_GL_DrawArrowRight,
		AG_GL_DrawBoxRounded,
		AG_GL_DrawBoxRoundedTop,
		AG_GL_DrawCircle,
		AG_GL_DrawCircleFilled,
		AG_GL_DrawRectFilled,
		AG_GL_DrawRectBlended,
		AG_GL_DrawRectDithered,
		AG_GL_UpdateGlyph,
		AG_GL_DrawGlyph,
		AG_GL_StdDeleteList
	},
	COCOA_OpenWindow,
	COCOA_CloseWindow,
	COCOA_MapWindow,
	COCOA_UnmapWindow,
	COCOA_RaiseWindow,
	COCOA_LowerWindow,
	COCOA_ReparentWindow,
	COCOA_GetInputFocus,
	COCOA_SetInputFocus,
	COCOA_MoveWindow,
	COCOA_ResizeWindow,
	COCOA_MoveResizeWindow,
	COCOA_PreResizeCallback,
	COCOA_PostResizeCallback,
	NULL,				/* captureWindow */
	COCOA_SetBorderWidth,
	COCOA_SetWindowCaption,
	NULL,				/* setTransientFor */
	COCOA_SetOpacity,
	COCOA_TweakAlignment
};


text:
Aleksandr Zabelin, né le , est un tireur sportif soviétique puis russe.

Palmarès

Jeux olympiques d'été
 Jeux olympiques d'été de 1960 de Rome
  Médaille de bronze en pistolet feu rapide à 25m

Notes et références

Lien externe

Naissance en décembre 1931
Tireur sportif soviétique
Médaillé de bronze olympique soviétique
Tireur aux Jeux olympiques d'été de 1960

redpajama_set_name: RedPajamaWikipedia


Looking for Sleaford conveyancing solicitors?
Before you instruct a conveyancer, confirm that the firm can represent your mortgage lender.
Failing to confirm that your property lawyer is authorised to act for your lender can put your home move at risk of delay or failure.
What are the council tax bands in North Kesteven District Council?
How much are conveyancing fees for buying or selling a home in Sleaford?
Disbursements are the costs payable as part of a conveyancing transaction, incurred on behalf of a buyer or seller, for example Stamp Duty Land Tax (SDLT) or ground rent service charges. Legal fees are for the work our solicitors carry out for you.
I'm buying a home in Sleaford - which searches will I need?
Sometimes the location of the property will warrant further searches , for example a flood search.
To see the cost of searches on a Sleaford move, try our calculator.
I am buying a leasehold property in Sleaford - what do I need to know?
Buying a leasehold flat in the UK can be complicated. The many potential traps awaiting the unsuspecting purchaser can include legally technical issues like and freeholds sold without first refusal to leaseholders.
Is there anything to be aware of if selling a leasehold property in Sleaford?
The legal work for a leasehold flat (leasehold houses are not common) is significantly more protracted than for a freehold property.
The complexities of leasehold mean conveyancing solicitors in Sleaford will usually undertake additional tasks, for example requesting an up-to-date service charge statement, through to ascertaining if a license to assign is required.
So as to resolve any leasehold-related problems sooner, It is highly recommended that you instruct a conveyancer as early in the process as possible, and preferably before marketing the property,.
I am remortgaging a property in Sleaford - do I need a solicitor?
The official UK base rate is currently set at 0.75% (Feb 2019). A good Sleaford remortgage solicitor will complete the conveyancing process quickly and get you into your new rate.
Quittance's solicitors are members of most UK mortgage lenders, so whether you are you are switching to a flexible mortgage with Santander or to a joint mortgage with the Allied Irish Bank, we can help.


Two charging modes for improving efficiency.
Intelligent protection for safe use.
Only 12.44mm/0.49in thickness for easy taking and operation.
Silicone surface material against skidding and dropping.
Charging for Qi standard wireless mobile devices, such as iPhone X / 8 / 8 Plus, Samsung Galaxy S6 / S6 Edge / S6 Edge Plus / Note / S7 / S7 Edge / S8 / S8 Plus / Note 8, Xiaomi Mi Mix 2S, etc.
3. Not including wireless charging receiver. If your phone has no built-in wireless receiver, you need to plug a wireless receiver to charge.


text:
Q: Single for-loop Into Mult Columns(JAVA) I haven an assignment for school and I'm a beginner into Java. I did the ASCII char loops like I needed to, but I want it to look pretty.
How do I make a single for-loop into multiple columns to show up on the output screen without having to scroll?
public static void main(String[] args) {
   for (int i = 32; i <= 126; i++)
       System.out.println((char) i);
}//end main

A: Instead of using System.out.println, just use System.out.print, and on each iteration through the loop, check to see whether i % 8 == 7 (or the equivalent for some other line length). If it is, print a newline; otherwise, print a tab or some spaces.

redpajama_set_name: RedPajamaStackExchange


text:
Q: SBT Scoverage: Ignore value assignment I would like to ignore variable assignments in my project, for example something like this:
val someString = "123"

Will be considered as untested by scoverage, I could mark the line explicitly using comments:
// $COVERAGE-OFF$
val someString = "123"
// $COVERAGE-ON$

This is kinda hard at this point since the project is quite big and I don't really think comments should be used for this purpose.


text:
Cavs' Garland on losing to Pistons: 'This is a bad loss'
January 31, 2022 January 31, 2022 Categories UncategorizedCADE CUNNINGHAM, CAVALIERS, EVAB MOBLEY, JARRETT ALLEN, JB BICKERSTAFF, NBA, pistonsLeave a Comment on Cavs' Garland on losing to Pistons: 'This is a bad loss'
The Cleveland Cavaliers were hoping to make it four straight wins Sunday night when they headed into Detroit to battle the Pistons.
However, behind a game-high 31 points from Saddiq Bey and a triple-double from rookie Cade Cunningham, who had 19 points, 10 rebounds, and 10 assists, Detroit defeated the Cavs 115-105 at Little Caesars Arena.
Cleveland's(30-20) three-game winning streak is over, while the Pistons(12-37) snapped their four-game losing streak.
Here's the Great, Not So Great, and Bottom Line of the Cavs' loss to the Pistons.
The Great for the Cavaliers:
Darius Garland had a team-high 24 points, including a career-high-tying five threes, with seven assists and four rebounds. The third-year guard had a great second quarter as he scored 12 points, including three threes.
-Evan Mobley was in double figures once again as he scored 18 points, grabbed nine rebounds, and added three blocks. This was Mobley's 17th consecutive game in double figures. In addition, Mobley has recorded 21 multi-block games, the most by a Cavs rookie since Tristan Thompson's 20 multi-block games during the 2011-12 season.
–The first four minutes of the first quarter: Cleveland got out early on the Pistons and led 15-0 at the 8:03 mark of the first quarter, which was their largest lead of the game. The Cavs made their first four shots, and it appeared Cleveland would run away with the game, but they only led 29-24 after one.
The Not So Great for the Cavaliers:
Rebounding: The Pistons outrebounded the Cavs 48-41. Cleveland allowed 16 offensive rebounds, and Detroit had 20 second-chance points.
Points in the paint: Detroit had a good time in the lane. The Pistons scored 64 of their 115 points in the paint. The Cavs had a hard time keeping the Pistons out of the paint, which cost them Sunday night.
Fourth Quarter: With 9:02 left in the fourth, the Cavs led 98-89. However, the Pistons would go on a 22-2 run and take a 111-100 lead with just under a minute left in the game. The 11-point lead was Detroit's largest lead of the night. Detroit shot 61% from the field, including 60% from downtown in the quarter. Cleveland had seven turnovers in the fourth and shot 38% from the floor. The Pistons outscored the Cavs 31-17 in the final period.
Cleveland had their best win of the season when they beat the defending champions, the Milwaukee Bucks, Wednesday night, and this loss to the Pistons might have been the worst loss of the season. This is a bad loss for the Cavs, and there's no other way to look at it. They led early and fell apart late. These are the types of losses that you regret later in the season.
However, when you're a young team, losses like this happen, but they can't let it happen again.
"This is a bad loss, and it is going to stick in my mind," Garland said postgame.
What's Next:
Cleveland gets right back at it Monday night when they head home to battle the Pelicans.
Jarrett Allen had 15 points, nine rebounds, and two blocks. Dean Wade added 14 points, and Cedi Osman chipped in with 13 points off the Cavs' bench.
-Isaiah Stewart had a double-double with 14 points and a game-high 12 rebounds; Frank Jackson added 19 points off the Pistons' bench.
Watch below as Garland talks loss to the Pistons:
Previous Post Carlisle on Mavs: 'That's a team that's got a real chance, not only to come out of the West, but they're a good contender'
Next Post Vikings' Kirk Cousin added to Pro Bowl roster

redpajama_set_name: RedPajamaCommonCrawl


Stromness ferry port in Orkney Islands connects you with Scrabster in Scotland with a choice of up to 21 ferry crossings per week. The duration of the Stromness to Scrabster crossing is from 1 hour 30 minutes and the crossing is operated by Northlink Ferries.
Stromness has to be one of the most enchanting ports at which to arrive by boat, its picturesque waterfront a procession of tiny sandstone jetties and slate roofs nestling below the green hill of Brinkies Brae. Its natural sheltered harbour (known as Hamnavoe) must have been used in Viking times, but the town itself only really took off in the eighteenth century.
The old town of Stromness still hugs the shoreline, its one and only street, a narrow winding affair, built long before the advent of the motor car, still paved with great flagstones and fed by a tight network of alleyways or closes. The central section, which begins at the Stromness Hotel, is known as Victoria Street. On the east side of the street the houses are gable-end-on to the waterfront, and originally each one would have had its own pier, from which merchants would trade with passing ships.
If you need to spend a night at or near Stromness ferry port before or after your trip or if you are looking for accommodation for your entire stay, please visit our Stromness Accommodation page for the best accommodation prices and one of the largest selections available online!
You have been added to the directferries.ie mailing list.


Ted Gonder is the co-founding CEO of Moneythink, the only movement of young people restoring the economic health of the United States through preventative, transformative, and evidence-driven youth financial education. Since 2009, Moneythink has trained over 1000 college leaders to serve as financial mentors and college role models to over 12000 teenagers across 10 states. From March 2014 to June 2015, he was also a member of the U.S. President's Advisory Council on Financial Capability for Young Americans.
Prior to Moneythink, Ted served as Entrepreneur-in-Residence at the U.S. Department of Homeland Security, advising the Obama Administration on immigration policy for foreign entrepreneurs. Previously, he worked with the Kauffman Foundation and the Chilean government on transnational entrepreneurship initiatives, and published research on the topic through MIT Press and McKinsey. Ted got his start in social entrepreneurship leading a number of climate-change-related student initiatives, most notably being appointed and serving as the student advisor to The Climate Project, an organization founded by Al Gore.
His work has been featured in MTV, WSJ, and Crain's; and has spoken at the White House, U.S. Senate, NYSE, TEDx, and at top companies such as PwC, IDEO, Dell, and Allstate.
Besides work, Ted enjoys his wife and son, practicing martial arts, admiring wild animals, and writing on his blog.


text:
class CreateSpreeGlobalCollectCheckout < ActiveRecord::Migration
  def change
    create_table :spree_global_collect_checkouts do |t|
      t.string :order_number
    end
  end
end

redpajama_set_name: RedPajamaGithub


text:
Saint of the Day - Blessed Charles the Good
Blessed Charles the Good (1083–1127), also known as Charles I and the Count of Flanders, was born in Denmark, the only son of King Canute IV (St. Canute) and Adela of Flanders. He was five years old when his father was assassinated in the Odense Cathedral, after which he and his mother fled for their lives to Flanders. He grew up in the royal court in that country and accompanied his maternal grandfather, a Count, on a crusade to the Holy Land. After his grandfather's death, Blessed Charles became an advisor to the next Count, his uncle; after his uncle's death, Charles became Count. He was highly regarded by the people for his holiness and virtue. He was outspoken against the common practice of hoarding grain and selling it at inflated prices, and opposed the prominent Erembald family who gained their financial prosperity through this unjust practice. On March 2, 1127, while Charles was in church praying, he was slain by soldiers loyal to the Erembald family, in the same manner his father was killed. His death sparked a public outcry and uprising against the Erembald family, while Charles was immediately looked upon as a martyr and saint. His feast day is March 2nd. For more information please see morningoffering.com/2022-03-02/.


We have here the end of an era and another one established and several loose ends brought to conclusion. David gives wise counsel to Solomon that is fitting for all: follow God and His word! To think how things would have been different if they only had. As one reads 1 and 2 Kings and Chronicles, we see there are far more kings that are unfaithful. How foolish were they to not follow God and so are any of us who don't. David also asks Solomon to deal with his friends and his enemies in ways fitting for both. The end of Joab's life is sad. He was a man almost too loyal to David to the extent of misjudging what David wanted and thereby doing what he thought was best. But David and he went through a lot and Joab did many things to help David. It is a reminder that a few bad things can corrupt a lot of good things.
And Shimei just proves to be the fool he really was. He criticized David when he was down, and David was gracious to him in spite of it. He then repents when David returns to power and is promised protection. Solomon provides the same protection with one condition. And Shimei is foolish to break it. And is killed as a result.


Hudson Ltd. (HUD) ("Hudson Group" or "Company"), a leader in North American travel retail, announced that Roger Fordyce has been appointed Chief Executive Officer of the Company, effective January 8, 2019. Mr Fordyce succeeds Joseph DiDomizio who is leaving the Company to pursue other interests.
Mr. Fordyce served as an Executive Vice President and Chief Operating Officer of Hudson Group until his appointment as Chief Executive Officer. Mr. Fordyce joined Hudson Group 30 years ago. As Executive Vice President and Chief Operating Officer, he was responsible for the day-to-day general management of the Company. Prior to joining Hudson Group, Mr. Fordyce held positions as manager at Dobbs/Aeroplex, WH Smith, and Greenman Bros.
Mr. DiDomizio will also leave the Board of Directors of the Company. In that respect, Hudson Ltd. also announced the Notice of a Proposed Shareholder Written Resolution which if passed by the Company's shareholders will appoint Mr. Fordyce to succeed Mr. DiDomizio as a Class III Director of the Company until the Company's 2021 annual general meeting or until his office shall otherwise be vacated pursuant to the Company's bye-laws. The Proposed Shareholder Written Resolution will be passed when it is signed by registered shareholders who as of today (being the date the notice of the proposed resolution is given) hold a simple majority of the total voting rights of all issued and outstanding shares of the Company, provided such majority includes at least one shareholder holding Class B common shares of the Company.


text:
Low interannual variability in recent oceanic uptake of atmospheric carbon dioxide
Lee, K.; Wanninkhof, R.; Takahashi, T.; Doney, S. C.; Feely, R. A.
Gravity evidence of very thin crust at the Gakkel Ridge (Arctic Ocean)
Coakley, B. J.; Cochran, J. R.
Lower crustal extension across the Northern Carnarvon basin, Australia: Evidence for an eastward dipping detachment
Millennial-scale iceberg discharges in the Irminger Basin during the last glacial period: Relationship with the Heinrich events and environmental settings
Elliot, M.; Labeyrie, L.; Bond, G.; Cortijo, E.; Turon, J. L.; Tisnerat, N.; Duplessy, J. C.
On the origin and evolution of sea-ice anomalies in the Beaufort-Chukchi sea
Tremblay, L. B.; Mysak, L. A.
A Pilot Research Moored Array in the Tropical Atlantic (PIRATA)
Servain, J.; Busalacchi, A. J.; McPhaden, M. J.; Moura, A. D.; Reverdin, G.; Vianna, M.; Zebiak, S. E.
Spectral inversion of Lg from earthquakes: A modified method with applications to the 1995, western Texas earthquake sequence
Xie, J. K.
The Labrador Sea deep convection experiment
Marshall, J.; Dobson, F.; Moore, K.; Rhines, P.; Visbeck, M.; d'Asaro, E.; Bumke, K.; Chang, S.; Davis, R.; Fischer, K.; Garwood, R.; Guest, P.; Harcourt, R.; Herbaut, C.; Holt, T.; Lazier, J.; Legg, S.; McWilliams, J.; Pickart, R.; Prater, M.; Renfrew, I
On the utility and disutility of JEBAR
Cane, M. A.; Kamenkovich, V. M.; Krupitsky, A.
Upper Eocene tektite and impact ejecta layer on the continental slope off New Jersey
Glass, B. P.; Koeberl, C.; Blum, J. D.; McHugh, C. M. G.
Meteoritics & Planetary Science
Radiometrically determined sedimentary fluxes in the sub-polar North Atlantic during the last 140,000 years
McManus, J. F.; Anderson, R. F.; Broecker, W. S.; Fleisher, M. Q.; Higgins, S. M.
Fish scale evidence for rapid post-glacial colonization of an Atlantic coastal pond
Daniels, R. A.; Peteet, D.
Global Ecology and Biogeography
Seasonal variability of bio-optical and physical properties in the Arabian Sea: October 1994-October 1995
Dickey, T.; Marra, J.; Sigurdson, D. E.; Weller, R. A.; Kinkade, C. S.; Zedler, S. E.; Wiggert, J. D.; Langdon, C.
Variability in primary production as observed from moored sensors in the central Arabian Sea in 1995
Marra, J.; Dickey, T. D.; Ho, C.; Kinkade, C. S.; Sigurdson, D. E.; Weller, R. A.; Barber, R. T.
The changing relationship between ENSO variability and moisture balance in the continental United States
Cole, J. E.; Cook, E. R.
Interannual variability in western US precipitation
Rajagopalan, B.; Lall, U.
Variability of Delta pCO(2) in the subarctic North Pacific. A comparison of results from four expeditions
Murphy, P. P.; Harrison, D. E.; Feely, R. A.; Takahashi, T.; Weiss, R. F.; Gammon, R. H.
Tellus Series B-Chemical and Physical Meteorology
Distribution of helium and tritium in Lake Baikal
Hohmann, R.; Hofer, M.; Kipfer, R.; Peeters, F.; Imboden, D. M.; Baur, H.; Shimaraev, M. N.
A reassessment of U-Th and C-14 ages for late-glacial high-frequency hydrological events at Searles Lake, California
Lin, J. C.; Broecker, W. S.; Hemming, S. R.; Hajdas, I.; Anderson, R. F.; Smith, G. I.; Kelley, M.; Bonani, G.
Flow of river water into a karstic limestone aquifer - 2. Dating the young fraction in groundwater mixtures in the Upper Floridan aquifer near Valdosta, Georgia
Plummer, L. N.; Busenberg, E.; Drenkard, S.; Schlosser, P.; Ekwurzel, B.; Weppernig, R.; McConnell, J. B.; Michel, R. L.
Applied Geochemistry
Global deep-sea burial rate of calcium carbonate during the last glacial maximum
Catubig, N. R.; Archer, D. E.; Francois, R.; deMenocal, P.; Howard, W.; Yu, E. F.
Deformation of the Caribbean region: One plate or two?
Driscoll, N. W.; Diebold, J. B.
Morphology of the transition from an axial high to a rift valley at the Southeast Indian Ridge and the relation to variations in mantle temperature
Shah, A. K.; Sempere, J. C.
A multivariate frequency-domain approach to long-lead climatic forecasting
Rajagopalan, B.; Mann, M. E.; Lall, U.
Weather and Forecasting
Hydrothermal vents near a mantle hot spot: The Lucky Strike vent field at 37 degrees N on the Mid-Atlantic Ridge
Langmuir, C.; Humphris, S.; Fornari, D.; VanDover, C.; VonDamm, K.; Tivey, M. K.; Colodner, D.; Charlou, J. L.; Desonie, D.; Wilson, C.; Fouquet, Y.; Klinkhammer, G.; Bougault, H.
Ejecta layer at the Cretaceous-Tertiary boundary, Bass River, New Jersey (Ocean Drilling Program Leg 174AX)
Olsson, R. K.; Miller, K. G.; Browning, J. V.; Habib, D.; Sugarman, P. J.
Groundwater record of halocarbon transport by the Danube River
Bohlke, J. K.; Revesz, K.; Busenberg, E.; Deak, J.; Deseo, E.; Stute, M.
The southeast Indian ridge between 88 degrees E and 118 degrees E: Gravity anomalies and crustal accretion at intermediate spreading rates
Cochran, J. R.; Sempere, J. C.
The southeast Indian ridge between 88 degrees E and 118 degrees E: Variations in crustal accretion at constant spreading rate
Sempere, J. C.; Cochran, J. R.
From volcano to sediment: Dynamics of the submarine volcaniclastic apron of Gran Canaria, Canary Islands (eastern Atlantic Ocean, ODP Leg 157)
Schneider, J. L.; Gerard, M.; Schmincke, H. U.; Weaver, P. P. E.; Firth, J.; Baraza, J.; Bristow, J. F.; Brunner, C.; Carey, S. N.; Coakley, B.; Fuller, M.; Funck, T.; Goldstrand, P.; Herr, B.; Hood, J.; Howe, R.; Jarvis, I.; Lebreiro, S.; Lindblom, S.; L
Comptes Rendus De L Academie Des Sciences Serie Ii Fascicule a-Sciences De La Terre Et Des Planetes
Asian provenance of glacial dust (stage 2) in the Greenland Ice Sheet Project 2 Ice Core, Summit, Greenland
Biscaye, P. E.; Grousset, F. E.; Revel, M.; VanderGaast, S.; Zielinski, G. A.; Vaars, A.; Kukla, G.
Thermal history of the eastern Gulf of Suez, II. Reconstruction from apatite fission track and Ar-40/Ar-39 K-feldspar measurements
Kohn, B. P.; Feinstein, S.; Foster, D. A.; Steckler, M. S.; Eyal, M.
Improving estimates of total tree ages based on increment core samples
Villalba, R.; Veblen, T. T.
Sensitivity of northern hemisphere air temperatures and snow expansion to North Pacific sea surface temperatures in the Goddard Institute for Space Studies general circulation model
Peteet, D.; DelGenio, A.; Lo, K. K. W.
A new assessment of possible solar and lunar forcing of the bidecadal drought rhythm in the western United States
Cook, E. R.; Meko, D. M.; Stockton, C. W.
Minor and trace element chemistry of Lake Baikal, its tributaries, and surrounding hot springs
Falkner, K. K.; Church, M.; Measures, C. I.; LeBaron, G.; Thouron, D.; Jeandel, C.; Stordal, M. C.; Gill, G. A.; Mortlock, R.; Froelich, P.; Chan, L. H.
The ultrafast East Pacific Rise: Instability of the plate boundary and implications for accretionary processes
Cormier, M. H.
Philosophical Transactions of the Royal Society of London Series a-Mathematical Physical and Engineering Sciences
Magde, L. S.; Sparks, D. W.; Detrick, R. S.
Three-dimensional mantle upwelling, melt generation, and melt migration beneath segment slow spreading ridges
Magde, L. S.; Sparks, D. W.
A model of rift basin evolution constrained by first-order stratigraphic observations
Contreras, J.; Scholz, C. H.; King, G. C. P.
Orbital forcing of climate over South Africa: A 200,000-year rainfall record from the Pretoria Saltpan
Partridge, T. C.; deMenocal, P. B.; Lorentz, S. A.; Paiker, M. J.; Vogel, J. C.
Bathymetric roughness of the southeast Indian ridge: Implications for crustal accretion at intermediate spreading rate mid-ocean ridges
Ma, L. Y.; Cochran, J. R.
Stochastic analysis of seafloor morphology on the flank of the southeast Indian ridge: The influence of ridge morphology on the formation of abyssal hills
Goff, J. A.; Ma, Y.; Shah, A.; Cochran, J. R.; Sempere, J. C.
The late Eocene House Range Flora, Sevier Desert, Utah: Paleoclimate and paleoelevation
Palaios
The origin of abyssal peridotites: a new perspective
Niu, Y. L.; Langmuir, C. H.; Kinzler, R. J.
Global air-sea flux of CO2: An estimate based on measurements of sea-air pCO(2) difference
Takahashi, T.; Feely, R. A.; Weiss, R. F.; Wanninkhof, R. H.; Chipman, D. W.; Sutherland, S. C.; Takahashi, T. T.
The use of H-3 and tritiogenic He-3 to determine CFC degradation and vertical mixing rates in Framvaren Fjord, Norway
Shapiro, S. D.; Schlosser, P.; Smethie, W. M.; Stute, M.
Stratigraphic record of the early Mesozoic breakup of Pangea in the Laurasia-Gondwana rift system
Olsen, P. E.
Annual Review of Earth and Planetary Sciences
Monsoon fluctuations over the past 350 kyr: High-resolution evidence from northeast Asia northwest Pacific climate proxies (marine pollen and radiolarians)
Heusser, L.; Morley, J.
A sediment trap experiment in the Vema Channel to evaluate the effect of horizontal particle fluxes on measured vertical fluxes
Gardner, W. D.; Biscaye, P. E.; Richardson, M. J.
A review of melt migration processes in the adiabatically upwelling mantle beneath oceanic spreading ridges
Kelemen, P. B.; Hirth, G.; Shimizu, N.; Spiegelman, M.; Dick, H. J. B.
Forcing of Atlantic equatorial and subpolar millennial cycles by precession
McIntyre, A.; Molfino, B.
Bourdon, B.; Langmuir, C. H.; Zindler, A.
Sub-bottom temperature anomalies detected by long-term temperature monitoring at the TAG hydrothermal mound
Kinoshita, M.; Matsubayashi, O.; VonHerzen, R. P.
Combined laboratory and numerical studies of the interaction between buoyant and plate-driven upwelling beneath segmented spreading centers
Magde, L. S.; Kincaid, C.; Sparks, D. W.; Detrick, R. S.
Cadmium in the California current system: Tracer of past and present upwelling
Van Geen, A.; Husby, D. M.
Long-lived oceanic transform boundaries formed above mantle thermal minima
Oceanography - Communication between oceans
Gordon, A. L.
The eastern boundary of the Gulf Stream recirculation
Marchese, P. J.; Gordon, A. L.
Southern Ocean fronts from the Greenwich meridian to Tasmania
Belkin, I. M.; Gordon, A. L.
Eddies of newly formed upper Labrador Sea water
Pickart, R. S.; Smethie, W. M.; Lazier, J. R. N.; Jones, E. P.; Jenkins, W. J.
Lower Cretaceous deposits trapped near the equatorial Mid-Atlantic Ridge
Bonatti, E.; Ligi, M.; Borsetti, A. M.; Gasperini, L.; Negri, A.; Sartori, R.
Provenance of icebergs during Heinrich event 3 and the contrast to their sources during other Heinrich episodes
Diffuse impact of the Mid-Atlantic Ridge with the Romanche transform: An ultracold ridge-transform intersection
Bonatti, E.; Ligi, M.; Carrara, G.; Gasperini, L.; Turko, N.; Perfiliev, S.; Peyve, A.; Sciuto, P. F.
High-resolution stratigraphy of the Newark rift basin (early Mesozoic, eastern North America)
Olsen, P. E.; Kent, D. V.; Cornet, B.; Witte, W. K.; Schlische, R. W.
Direct U-Th dating of marine sediments from the two most recent interglacial periods
Slowey, N. C.; Henderson, G. M.; Curry, W. B.
The relative importance of plate-driven and buoyancy-driven flow at mid-ocean ridges
Kincaid, C.; Sparks, D. W.; Detrick, R.


text:
Zombie Franchises: X-Men
By Kenneth Lowe | July 1, 2019 | 9:33am
Movies Features zombie franchises
"Who's that?" asked my girlfriend's 14-year-old son in our screening of Dark Phoenix, referring to a randomly levitating Michael Fassbender. (He is Magneto, Master of Magnetism and leader of the Brotherhood of Mutants, but you wouldn't know that from the movie, which insists on just calling him "Eric" and never once providing exposition about his powers.)
He is not a sheltered kid when it comes to the big tentpole films of summer and Christmas, but he mentioned, after a trailer for Dark Phoenix played before one of the umpteen Marvel movies I've taken him to see, that he didn't know anything about one of the biggest superhero series ever. For sheer curiosity and because I had a ton of rewards points at my theater, I took him along to see the last installment in the series—at least the last in this continuity—that truly kicked off the superhero film phenomenon. (He thought it was fine, but justifiably needed help identifying characters, none of whom just use their damn names from the comics.)
It's a good thing we saw it while we could: It was pulled from many theaters within just a month due to lackluster performance. With Avengers: Endgame and Dark Phoenix debuting this year as the end of their respective narratives and the inside baseball news of Disney simply buying the parent company that owns the film rights to the X-Men, it's worth it to consider why these movies trudged haltingly along for as long as they did and why, even as we are unlikely to see this cast or this continuity continue, we unquestionably are going to see some kind of reboot or revival.
The proliferation of superhero films over the past 20 years has diminished the importance of the X-Men movies in a way. It's wrong to say 2000's X-Men was the first comic book movie of the current era: 1998's Blade was. It's wrong to say it was the first to be unapologetically faithful to its source material: The movie scoffed at the "yellow spandex" of the comics, wrapping its characters in black leather, while 2002's Spider-Man happily featured its eponymous wall-crawler tangling with the Green Goblin in costumes that fully evoked their four-color roots.
If the first movie has anything going for it in the grand history of this mega-genre, it's that it cast giants like Patrick Stewart and Ian McKellen and has a plot recognizably based on comics in a digestible format. If you weren't immersed up to your telepathy-proof helmet in the lore of the comics but had an understanding of the X-Men story, the movie did great work getting you up to speed and invested quickly, with no jarring changes to series lore because grown men were afraid to say words like "mutants" or "Cerebro."
It also made the wise decision to focus the narrative on one character—Hugh Jackman's Wolverine, the bad boy of the team and the perfect audience surrogate. Handing the duty of perspective character to the X-Men's consummate loner made the introduction to the weird world of Professor Charles Xavier and his team of extracurricular vigilantes seem natural.
X-Men was okay, and didn't make any missteps in its plot or casting, but X2: X-Men United (2003) was, and I think still is, the strongest entry in the series, and was for a while a tight contender for strongest superhero movie of all time alongside Spider-Man 2, which came out the next year and unquestionably demonstrated that Marvel superheroes could compete with the likes of Superman and Batman at the box office.
X2 expanded the scope of the story, introduced a larger cast of characters, and came jam-packed with even more good action scenes. It kept Wolverine centered as the protagonist, introduced more nuance into the bad guys, and is responsible for some truly iconic moments, including the insane teleporting gunfight featuring Nightcrawler (Alan Cumming) and the yet-to-be-topped scene where McKellen's Magneto springs himself from his plastic prison.
It was after this point that Bryan Singer—and rest assured, we will get to him—left to work on the utterly forgettable Superman Returns, leaving the franchise he'd built in the hands of Brett Ratner for X-Men: The Last Stand. That latter film is where the franchise finally stumbled, and never recovered.
After the legendarily bad Wolverine standalone film X-Men Origins: Wolverine in 2009, the series pivoted to the inexplicably well-regarded X-Men: First Class, a movie which is very bad and yet which continues to set the aesthetic and continuity template for all the rest of these movies. First Class, which is a very bad movie that for some reason lots of reviewers really liked, shot the timeline backward to the 1960s and completely rebooted almost everything about the story in ways that to this day make no sense in the context of the original films, two of which were pretty okay.
For some reason, First Class is consistently mentioned as one of the good films in the series, I assume due to either the MTV Movie Awards-grade makeup and costuming effects or the killing of the only black character in loving, CGI-assisted slow motion.
At the same time the X-Men movies were faltering, Marvel Studios' lineup of Avenger's films were raking in cash and acclaim, and the moviegoers who knew about the origins of the characters began to question just exactly why Hugh Jackman couldn't be on screen trading one-liners with Robert Downey Jr. I don't know if it's true whether there's some kind of implicit Marvel bias in audience members, but it isn't the reason one of the biggest superhero teams in comics started losing at the box office to the previously ignored Avengers. It happened in part because the X-Men franchise spiraled out of anything resembling control, yet never stopped just making more movies. X-Men Origins: Wolverine was a canon-hostile movie that squandered every interesting idea it had. A second Wolverine solo film would also fail to make an impression.
Billed as a return to form, X-Men: Days of Future Past brought Singer back to the director's chair and cast Jackman as Wolverine in more than a mere cameo role, and it is also not a good movie, and one that somehow both raises a middle finger to the people who worked on the franchise after Singer left it and manages to be really confusing as it rips continuity to shreds once more. (It seems like Wolverine's time travel tinkering prevents the doomsday of the future and returned us to the original cast, including Stewart and Famke Janssen's Jean Grey for goodness sake, but then we abandon those castings completely in the mainline films.) The series defiantly kept Singer behind the camera as director and producer on the films as sexual assault allegations mounted against him—he did finally bow out for Dark Phoenix.
Dark Phoenix doesn't act as much of a send-off to its characters, doesn't neatly tie up any long-running plot points or do much to act as a statement on anything. It insists it is part of the same storied lineage as the X films that gave us the Stewart/McKellen rivalry or the dry charisma of Jackman's Wolverine, but it says virtually nothing about any of the central ideas the X-Men stand for. We absolutely are going to see more of them now that Disney has swallowed the franchise whole—there is no way they won't somehow be funneled carefully into the Marvel Cinematic Universe via some ridiculously ornate cameo in which Doctor Strange accidentally opens a portal to the X Mansion or Professor X asks T'Challa for political asylum in Wakanda.
This will necessarily mean throwing out what's come before, or blithely retconning it. The very first scene in the very first movie is one of the best ones in all of superhero films to date, a thing I don't say lightly in regard to anything that invokes the Holocaust: A terrified child ripped from his family reaches out and wrenches apart a metal fence through the power of will alone in the moment before he's knocked unconscious. It's him, a teenaged me thought in awed disbelief, because movies just didn't do that with superheroes. It's a trick filmmakers forgot about until we were introduced to Killmonger in almost the exact same way.
As Marvel scoops its intellectual property back into its toy chest, will their filmmakers match that artistry in service to these characters, who more than any others in comics represent the marginalized and disenfranchised? I'm really worried they won't.
Kenneth Lowe goes where he wants to go. You can follow him on Twitter or read more of his work at his blog.
zombie franchises
GET PASTE RIGHT IN YOUR INBOX
The best music, movies, TV, books, comedy and more.
Yes, I would like to receive Paste's newsletter
More from zombie franchises
Zombie Franchises: Robin Hood (and All Western Folklore)By Kenneth LoweNovember 20, 2018 | 9:49pm
Zombie Franchises: Jurassic ParkBy Kenneth LoweJune 27, 2018 | 10:02pm
Zombie Franchises: TerminatorBy Kenneth LoweMay 1, 2018 | 3:03pm
Zombie Franchises: God's Not DeadBy Kenneth LoweApril 8, 2018 | 1:09pm
Zombie Franchises: TransformersBy Kenneth LoweFebruary 2, 2018 | 6:26pm
Also in Movies
10 Years Ago, Movie 43 Set a New Low for Bad Sketch Comedy By Jim Vorel and Kenneth Lowe January 25, 2023 | 10:00am
Oscar Nominations 2023: The Good, the Bad and the Ugly By Jacob Oller & Anna McKibbin January 24, 2023 | 3:55pm
In The Treasure of the Sierra Madre, Bogie Broke Bad By Kenneth Lowe January 24, 2023 | 10:00am
Why So Many Actors Want To Become Directors By Anna McKibbin January 20, 2023 | 2:35pm
The House on Sorority Row Remains One of the Slasher Boom's Smartest Films By Matthew Jackson January 20, 2023 | 10:00am
Can We All Acknowledge That a Friday the 13th Prequel Series Is a Terrible Idea? By Jim Vorel January 19, 2023 | 12:30pm
The Best Comedies on Netflix Right Now (January 2023) By Garrett Martin and Paste Staff January 17, 2023
The 50 Best Movies on HBO Max, Ranked (January 2023) By Paste Movies Staff January 20, 2023
The 40 Best Horror Movies on Amazon Prime Video Right Now (Jan. 2023) By Jim Vorel January 3, 2023
More Movie Most Popular
Hypocritical Razzie Awards Introduce 18 Year Age Limit After Criticism, Ignore Past Child Actor Bullying By Jim Vorel January 25, 2023
Oscar Nominations 2023: Every Movie Honored by the Academy By Anna McKibbin January 24, 2023
Dungeons & Dragons Drops Expensive-Looking New Trailer By Jim Vorel January 23, 2023
New Scream 6 Trailer Gives Us First Glimpse at Returning Characters By Jim Vorel January 19, 2023
More Movies News


text:
Photos courtesy of Chuck Stowe.
KNOXVILLE, Iowa (August 7, 2018) – The 28th annual 360 Knoxville Nationals turned out to be one of the best weekends of Thomas Kennedy's careerto date. Kennedy upset the stout field in attendance by claiming the preliminary night feature win.
Kennedy grabbed the lead on the lap two restart after starting on the outside of the front row. Kennedy went on to lead the remainder of the 20-lap feature, but heavy pressure was applied in the closing laps.
Kennedy had a left rear tire going down on his Buffalo Wild Wings / Kennedy Floorings No. 21K, which allowed polesitter, Mason Daniels, to close in with five to go. A hard-charging Sammy Swindell cruised by Daniels on the following lap and quickly set his sights on Kennedy.
Swindell had a run and momentarily pulled even with Kennedy in the final set of corners coming to the checkered flag, but Kennedy slammed the door shut on the exit of turn four to earn his first career win at Knoxville Raceway.
"I was struggling to get through lapped traffic there. Sam [Hafertepe] and everyone else seemed to be the same pace I was, and I knew I was losing a lot of momentum and I looked at the board and I see the No. 3 car was there and he's the veteran of the veterans at this track and when I seen him underneath me for the checkered I went no way you're passing me," said Kennedy of his run and final trip to the front straightaway in victory lane.
With the win, Kennedy became the first Canadian driver to win a 360 Sprint Car race at the famed Marion County Fairgrounds.
Kennedy earned the eighth starting position for Saturday night's $15,000-to-win 360 Knoxville Nationals A-main.
During the championship feature, restarts were the key for Kennedy. On a track that was one-lane dominant around the top side in the early going, Kennedy picked off positions nearly every restart. In the second half of the race, Kennedy snuck around the outside of Gio Scelzi and Greg Hodnett in turn one, putting him in the fifth position.
Kennedy was closing in on Joey Saldana for fourth when the low side of the speedway began to take rubber. Kennedy held on to take the checkers in the fifth position, marking his best career finish at the 360 Nationals.
The busy weekend of racing concluded Sunday at Knoxville's Capitani Classic. After slipping back in his heat, Kennedy was in solid position to grab a transfer spot in the B-main. After starting fifth, Kennedy was working on Hodnett for fourth when issues with the ignition box sent Kennedy to the pits on lap two, ending his night.
Kennedy will qualify for the 58th annual 5-hour energy Knoxville Nationals on Thursday, August 9th.
Free, live audio can be found at dirtvision.com. Live, pay-per-view video will be available at thecushion.com.
← Jade Hastings Scores Second Win of 2018 at Devils Lake Speedway
Pederson Charges to Top Five at River Cities →
Kennedy Races to Second Win of 2018 at Wagner Speedway
May 9, 2018 Mike Spieker 0
November 28, 2019 Mike Spieker 0
July 20, 2018 Mike Spieker 0


text:
Emil Pacheco Pinheiro (1923 — Rio de Janeiro, 16 de julho de 2001) foi um contraventor e também presidente do Botafogo de Futebol e Regatas entre 1991 e 1992. Além de presidente do clube, ele também foi um dos principais diretores do Botafogo no final da década de 1980. Emil Pinheiro era bicheiro e, com o seu dinheiro, pôde investir na formação de um time forte.

Botafogo
Seu Emil, como era carinhosamente chamado, chegou ao clube em 1986. Porém, foi a partir de 1988 que seus investimentos ganharam mais força. Ele montou o time botafoguense campeão estadual em 1989, após 21 anos sem conquistas. Além disso, em 1990, sua equipe repetiu a façanha, com direito a vitória nos tribunais numa polêmica envolvendo o Vasco da Gama de Eurico Miranda.

Chegou ao cargo de presidente do Botafogo em 1991 e, no primeiro semestre de 1992, o clube chegou à final do Campeonato Brasileiro contra o Flamengo. Apesar de ser favorito, a derrota por 3 a 0 no primeiro jogo da final e a suspeita de suborno à jogadores do clube levaram Emil Pinheiro a afastar uma série de jogadores do clube que seria vice-campeão nacional. Após este episódio, Emil deixou o cargo de presidente do clube e com ele seus investimentos.

Morte
Emil Pinheiro morreu no Rio de Janeiro em 16 de julho de 2001 em decorrência do Mal de Parkinson num hospital na Barra da Tijuca. Ficou muito tempo sem se movimentar e sair de casa.

Dirigentes esportivos do Brasil
Emil
Presidentes do Botafogo de Futebol e Regatas
Mortes por doença de Parkinson


I've written a lot of memos to clients over the last 24 years – well over a hundred. One I'm particularly proud of is The Race to the Bottom from February 2007. I think it provided a timely warning about the capital market behavior that ultimately led to the mortgage meltdown of 2007 and the crisis of 2008. I wasn't aware and didn't explicitly predict (in that memo or elsewhere) that the unwise lending practices that were exemplified in sub-prime mortgages would lead to a global financial crisis of multi-generational proportions. However, I did detect carelessness-induced behavior, and I considered it worrisome.
As readers of my memos know, I believe strongly that (a) most of the key phenomena in the investment world are inherently cyclical, (b) these cycles repeat, reflecting consistent patterns of behavior, and (c) the results of that behavior are predictable.
Of all the cycles I write about, I feel the capital market cycle is among the most volatile, prone to some of the greatest extremes. It is also one of the most impactful for investors. In short, sometimes the credit window is open to anyone in search of capital (meaning dumb deals get done), and sometimes it slams shut (meaning even deserving companies can't raise money). This memo is about the cycle's first half: the manic swing toward accommodativeness.
An aside: I recently engaged in an exchange with a reader who took issue with my use of the word "cycle." In his view, something is a cycle only if it's so regular that the timing and extent of its ups and downs can be predicted with certainty. The cycles I describe aren't predictable as to timing or extent. However, their fluctuations absolutely can be counted on to recur, and that's what matters to me. I think it's also what Mark Twain had in mind when he said "History doesn't repeat itself, but it does rhyme." The details don't repeat, but the rhyming patterns are extremely reliable.


text:
Q: Como abrir uma página externa no phonegap ao clicar? hoje comecei a desenvolver utilizando PhoneGap, porém me deparei com um problema, que é clicar em um link e não conseguir abrir uma página externa, como se fosse uma nova activity, como eu posso realizar esse procedimento só usando html,css e javascript ? Obrigado desde já.

A: Não é aconselhável abrir páginas externas dentro da própria aplicação Cordova. Se você precisa apenas abrir páginas externas, basta chamar o browser padrão do dispositivo por:
navigator.app.loadUrl("seuLink", { openExternal:true } );

Em último caso, se você precisar mesmo abrir uma página interna em seu App Cordova/PhoneGap, tente com iframe. No entanto, como dito, isso pode causar muito problemas na maneira como o App funciona (eventos de Backbutton, por exemplo, podem não funcionar mais como o esperado).
PS: Além disso, a partir do Cordova 4.0, foi implementado o plugin padrão de WhiteList. Talvez seja necessário configurar as páginas que você abrirá antecipadamente.
Espero que ajude. :)


Good chess players read chess books and don't make the same mistakes for the rest of their lives. They try to improve all the time to reach a higher level.
Learn effective opening lines and you will be able to play your first 12 moves or more in 2 minutes or faster.
First check out the downloadable UNIQUE videos created by Grandmaster Igor Smirnov. These high power chess teaching videos are VERY EFFECTIVE and will increase your playing strength rapidly.
Encyclopedia of Chess Openings, GM Roman Dzindzichashvili teaches you his own variations of play against 40 of the most popular openings. Books about Chess Openings!
Get "Logical Chess - Move by Move" by Chernev because every move is explained here!
Another good book for beginners that received very good reviews is the Complete Idiot's Guide to Chess.
I recommend the following chess strategy books for advanced players. There are many other good books around, but the following chess books are highly respected among chess players and myself.
It is commonly agreed among chess players that the following chess books are very good to improve your chess. Why are these books so good? It is the way how chess positions and chess moves are explained.
Jeremy has a way to explain that makes you understand things very fast. This is a natural gift he has. Some writers have it and some don't.
"The Amateur's Mind is eminently readable and instruction-rich. Jeremy Silman never disappoints those who seriously wish to improve their game."
One of the best chess authors is Mark Dvoretsky, who is a well known Russian chess trainer. Some people say, he is the best chess trainer in the world. His books are full of original ideas taken from his personal archives.
You can't buy anything better than that. But it's hard work to study these books and you should be a good chess player already, because these books will blow your mind away.
Grandmaster John Nunn, has written some outstanding chess books that are very enjoyable to read.
Polgar - 5334 Problems, Combinations & Games. This is one of the best chess books on Chess Tactics, which organizes 5,334 unique instructional positions! This book is written by the father of the Polgar sisters who all became Grandmasters. The book is widely known and has excellent reviews!
Get books written by John Watson, who is a well known chess writer.
You need one of the following chess programs to test your opening variations and analyze your games or to look up games in the database.
Good chess players use the Database from Chessbase OR alternatively the downloadable and excellent Russian product Chess Assistant to study and analyze chess variations and chess openings.
The most popular chess program is Fritz. I am sure, that every chess grandmaster on this planet uses Fritz to help analyze his games or prepare opening variations or to check the database to find games of his opponent. You can analyze your games with Fritz to find mistakes. Fritz is a German chess program produced by Frans Morsch and Mathias Feist. There is also a version that is called "Deep Fritz" and is designed for multi-processing.
Another top program is Shredder Chess, which has gained many computer world championship titles in recent years.
Replay Chess Games from Shredder and Rybka.
The best Chess Clocks are Premium Digital Chess Clocks.


text:
Borders MP vows to use committee role to speak up for region
Borders MP John Lamont has been made a member of Westminster's Scottish affairs committee.
Darin Hutson
Published: 07:28 Saturday 09 September 2017
Borders MP John Lamont has been given an extra chance to speak up for the region at Westminster after securing a place on the UK Parliament's Scottish affairs committee.
The Berwickshire, Roxburgh and Selkirk MP was nominated by fellow Conservative backbenchers for the role.
The committee's job is to hold the UK Government's Scotland Office, overseen by fellow Borders MP David Mundell in his role as Scottish Secretary, to account, including its relationship with the Scottish Parliament in Edinburgh.
It does that primarily by holding inquiries, and previous such probes have included ones on the 2016 European Union referendum's impact on Scotland and further devolution of powers to the Scottish Government.
The committee is chaired by Perth and North Perthshire MP Pete Wishart.
Mr Lamont is one of four Conservatives on it, the others being Aberdeen South's Ross Thomson, Banff and Buchan's David Duguid and East Renfrewshire's Paul Masterton.
The North Ayrshire-born 41-year-old, elected as an MP in June after 10 years as MSP for Ettrick, Roxburgh and Berwickshire, said: "I am delighted to have been confirmed as a member of the Scottish affairs committee at Westminster.
"Unlike in the Scottish Parliament, committees at Westminster are fiercely independent of government, and I will use this position to stand up for the Borders, leaving party politics to one side.
"I put myself forward for this because the Scottish affairs committee has an important role to play in ensuring the UK Government delivers for Scotland and for the Borders.
"Our work programme is still to be finalised, but we will inevitably be looking at how the Brexit negotiations impact on Scotland.
"I want to ensure we get a good deal for businesses and residents in the Borders. That means getting the best possible access to the EU market while gaining control over farming, business regulation and other key areas.
"I'd also like to focus on the implementation of the Borderlands growth deal."
"This policy has the potential to bring sustainable economic growth to the Borders, but only if we get the investment right."
Julie has daughter to thank for fourth bowls title in five years
This is how many points you'll get on your licence for these driving offences
Landmark bridge described as 'elegant'
More from Hawick News


Liechtenstein offers the perfect infrastructure for all kinds of conferences, congresses, seminars, excursions and other events.
From a simple meeting to a large conference, Liechtenstein offers high-quality services for groups of up to 700 people, as well as cosy hotels ideal for smaller functions. Let Liechtenstein Marketing help you make your event an experience to remember. And the best thing of all is that the country has so much to offer away from the conference location itself - culture, sport, fine food, valley tours and mountain adventures, to name but a few!
Liechtenstein is also a popular destination with organisers of group excursions. Party like a prince and let us help you create a made-to-measure programme of activities showing the best of the country. From architecture, culture and cuisine to fresh mountain air and traditional hospitality in the mountains, Liechtenstein has the perfect range of attractions and excursions for everyone.
Reward your clients and staff with a stay in Liechtenstein and experience the many attractions and activities on offer. Whether you opt to stay in a luxury hotel or go back to basics in a mountain hut, we will be pleased to put together a programme full of adventures, guided tours and cultural highlights that is sure to go down well with your guests.
With its full range of services, Liechtenstein Marketing is your partner for made-to-measure holidays and conferences in Liechtenstein. From state-of-the-art seminar facilities to attractive locations with a unique twist, it will be pleased to help you get the most out of your stay.
putting together an accompanying programme of activities.


iPad Air 2 Review – Why I Chose This iPad Over The Pro.
Recently I bought Sean and I an Apple iPad air 2. (He paid some money towards it don't worry). I spent a little time contemplating which one I should get.
But I am very happy with my choice, and I decided its time to tell you why. You may also be asking yourself the same question, and stuck on what one to buy.
Do I buy the new pro (9.7 inch), for a whole lot more money, or do I go with the new iPad Air? – That was the question my brain and Sean were fed up of hearing.. Yawn.
Now of course, if you have the money to spend on a pro, and you wont cry about it like I would have. (Still did over the Air 2..) then go ahead! Its an amazing device, with so many cool things and gadgets.
But I was not prepared, and not convinced enough.
So during this post I will be explaining my reason as to why I chose the iPad air 2.
I know it says this is a review in the title, and it kind of is, but for non tech-quick-answer kinds of people like me. I dont want to technical info, I just want a few convincing points!
(Before you read this, please keep in mind – this is my own opinion, I am not being horrible or slating Apple, I love Apple products, but this is a big-ish decision!
I have never had an iPad before – lets clear that up.
There are no older versions to compare the iPad air 2 with, but I guess my opinion can be valid, if you too, are someone buying an iPad for the first time.
I spent so much time I will never get back, thinking about what iPad to buy.. When the answer was pretty simple.
So if you are reading this post, you are doing the same thing I did – researching other opinions, to hopefully sway your own.
I am in love, yes still in love with the rose gold, which is NOT available in the iPad Air 2.
But the gold is still pretty nice in the iPad Air 2? But I couldn't possibly spend so much more, just because I liked the colour better… Actually I could have bought it to be honest, but I didn't need to.
I searched the internet looking for advice, reviews, videos, comparisons, and many of them said that the Pro just really isn't worth it if you do not need the new features – which I really didn't.
I also read that their are not enough differences between the two to justify the price of both of them.
The new features for the Pro is what really makes it expensive, I knew I wouldn't really use the nearly £100 Apple pen, or the keyboard, so that feature was pointless to me.
I wasn't too bothered about the back light feature either, I probably wouldn't even notice the difference, the speakers are better on the pro too, but yet again, not a big deal.
The Pro is also faster than the iPad Air 2, in the technical terms its a big difference, but comparing the two (I watched videos to find this out) you cannot really tell that the Air is slightly slower.
The sole purpose of my iPad air 2 is to up my game on social media, in order to boost the popularity of my blog. I also just wanted to treat myself and buy a new gadget, because its fun.
My iPad is used to plan, prepare, jot down draft notes, and share my posts everywhere.
Obviously i use it for fun, there are millions of apps and games for the iPad, so of course I spend some time (wasting it) playing games.
Face time! I never ever liked to face time on my phone, I have no idea why, but its so much more fun on the iPad air 2 now! The quality of the camera is better and you can still use your iPad whilst face timing.
Airdrop is such a great feature, especially if you have an iPhone too. I decided not to transfer my over 1,000 images onto my iPad, instead I just air drop the ones I need, and edit them on my iPad if I have it with me.
I use it to read and reply to emails, its just nicer having a bigger screen.
The camera is pretty good, not that I find it a convenient device to photograph with.
I make notes on everything! You can also draw cute little pictures on your iPad Air 2 on your notes, I also spend a lot of time doing this!
And that is it really… I guess I could use it for more, but I am still learning how it works! Overall, I love my iPad, and do not regret my decision, which is the main thing.
The iPad Pro in a nutshell – Apple 'claims' that this device could replace your laptop due to its pen and keyboard (which again, cost ridiculous amounts).
I mean, it probably could if you really like Apple products that much, but I personally think I will always use windows, and a 'proper' laptop (by this I mean NOT apple).
The iPad Air 2 in a nutshell – An updated version of the old iPad Air, and an iPad that has very little differences to the new 9.7 inch pro.
Still a great device, and does what ever you would need an iPad for, you just cant draw professionally on it, or have a keyboard that attached.
You can get Bluetooth keyboards for your iPad Air 2 (and any other iPad I think..) so you do not need to buy an expensive one.
Do you really want to draw on a device, and not have it on paper? I much prefer using paper to draw, make notes, and all that jazz. I think its more fun, and old fashioned. If you are a pro at drawing then go ahead, but its not the same experience really now is it?
The iPad Air 2 is for someone who is a first time buyer, and using the iPad daily for regular uses. (Probably most of you).
Apple iPad Pro 9.7 is for humans who are familiar with Apple, who can draw, and who want to have a new laptop.
iPad Pro also has an AMAZING camera, but again, if you aren't going to make many pictures with it, there's not much point, just buy a camera..
Thank you for reading this post, I hope you I have helped you make a decision!
Comment below if you have an iPad Air 2, and if you have any top tips!
Next Post High Street Trench Coat – Wear With Anything Coat!