text:
title: Paul Davey
summary: Painter, illustrator
date: 2015-03-05
categories:
- artist
- game
- illustrator
- mac
---

### Who are you, and what do you do?

I'm Paul Davey in the real world, [mattahan](http://www.mattahan.com/ "Paul's website.") online. I make paintings, illustrations, and a video game called [EarthNight][]. I used to make icons and I may someday make comics.

### What hardware do you use?

The machine on which I get all my work done is a [2011 MacBook Pro][macbook-pro]. Attached to it is a [Wacom Cintiq 13HD][cintiq]. I kinda want to upgrade, but I feel I'd be annoyed by the low pixel density of the larger Cintiqs (from 13 inch to 24 inch, all 1080p). Also, they're damn expensive.

I do research, planning, notes, and occasional sketching on my [iPad Air][ipad-air]. On my [IKEA BEKANT][bekant] desk that I hate (#bringbackgalant2015) are a pair of [M-Audio Studiophile AV 40s][studiophile-av-40], a [Kangaroo Pro][kangaroo-pro] standing desk, a [Dell something-something monitor][u2713hm] attached to a [Mac mini][mac-mini], and some shiny pebbles I got at The Smithsonian gift shop.

### And what software?

[Photoshop][] 90% of the time, [Manga Studio][manga-studio] and [Corel Painter][painter] the rest. I like the natural media blendiness of manga studio and painter, but can't stand their UIs. I've been sketching lately in [Autodesk Sketchbook Pro][sketchbook-pro] because of how quickly it launches and how smooth drawing in it feels, but it too has a terrible UI.

[Breaktime][] keeps me from getting headaches and back pain by reminding me to get up and blink. [Teleport][] makes both my Macs feel like one continuous system. [xGestures][] makes a keyboard unnecessary while I'm working on the Cintiq.

On [iOS][], I use [Drafts][drafts-ios] to capture ideas. It's earned prime real estate on both my iPhone and iPad home screens. From there those ideas become fleshed out [Evernote][] notes, or lengthier secret project things in [Editorial][editorial-ios].

[Overcast][overcast-ios] is my podcast client. I listen to podcasts while working to keep me sort of focused, my mind wanders in silence or with music playing. Mind wandering is awesome, it's where ideas are born, but it's not exactly conducive to getting things done.

### What would be your dream setup?

The Kangaroo Pro was me dipping my toe into the standing desk pool. Now that I'm *standing* in it, I'd like a larger, more stable sit-stand desk. Other than that and my tiny Cintiq, I'm pretty happy with my set up. I suppose I should get a proper drawing table, and I will eventually, but I just don't draw on paper that much anymore.

[bekant]: https://www.ikea.com/us/en/catalog/products/S19022530/ "A desk."
[breaktime]: https://itunes.apple.com/us/app/breaktime/id427475982 "A Mac tool that reminds you to take regular breaks.."
[cintiq]: https://www.wacom.com/en/us/cintiq "A computer screen you can draw on."
[drafts-ios]: https://agiletortoise.com/drafts/ "A note taking app."
[earthnight]: https://www.cleaversoft.com/ "An endless runner video game."
[editorial-ios]: http://omz-software.com/editorial/ "A Markdown-powered text app."
[evernote]: https://evernote.com/ "Online software for capturing notes."
[ios]: https://www.apple.com/ios/ios-10/ "A mobile operating system."
[ipad-air]: https://en.wikipedia.org/wiki/IPad_Air "A tablet device."
[kangaroo-pro]: https://www.ergodesktop.com/content/kangaroo-pro "An adjustable height desk."
[mac-mini]: https://www.apple.com/mac-mini/ "A small desktop computer."
[macbook-pro]: https://www.apple.com/macbook-pro/ "A laptop."
[manga-studio]: https://my.smithmicro.com/manga-studio-5.html "Comic and manga creation software."
[overcast-ios]: https://itunes.apple.com/us/app/overcast-podcast-player/id888422857 "A podcast app."
[painter]: https://www.painterartist.com/en/product/paint-program/ "Digital art software."
[photoshop]: https://www.adobe.com/products/photoshop.html "A bitmap image editor."
[sketchbook-pro]: https://www.autodesk.com/products/sketchbook-pro/overview "A drawing/illustration tool."
[studiophile-av-40]: http://www.m-audio.com/products/en_us/StudiophileAV40.html "Desktop speakers."
[teleport]: https://www.macupdate.com/app/mac/14042/teleport "Control multiple Macs with a single keyboard and mouse."
[u2713hm]: http://accessories.ap.dell.com/sna/productdetail.aspx?c=au&cs=audhs1&l=en&redirect=1&s=dhs&sku=210-40773 "A 27 inch LCD monitor"
[xgestures]: http://briankendall.net/xGestures/index.htm "Mac software for creating custom mouse gestures."


text:
class FDateTimeFormattingRules
{
	friend class FText;
public:
	FDateTimeFormattingRules()
		: AMDesignator(FString(TEXT("")))
		, DateSeparator(FString(TEXT("")))
		, TimeSeparator(FString(TEXT("")))
		, FirstDayOfWeek(0)
		, FullDateTimePattern(FString(TEXT("")))
		, LongDatePattern(FString(TEXT("")))
		, LongTimePattern(FString(TEXT("")))
		, MonthDayPattern(FString(TEXT("")))
		, PMDesignator(FString(TEXT("")))
		, RFC1123Pattern(FString(TEXT("")))
		, ShortDatePattern(FString(TEXT("")))
		, ShortTimePattern(FString(TEXT("")))
		, SortableDateTimePattern(FString(TEXT("")))
		, UniversalSortableDateTimePattern(FString(TEXT("")))
		, YearMonthPattern(FString(TEXT("")))
	{
	}

	FDateTimeFormattingRules(const TArray<FString>& InAbbreviatedDayNames, const TArray<FString>& InAbbreviatedMonthNames, const TArray<FString>& InDayNames, const TArray<FString>& InMonthNames, const TArray<FString>& InShortestDayNames, const FString InAMDesignator, const FString InPMDesignator, const FString InDateSeparator, const FString InTimeSeparator, const int InFirstDayOfWeek, const FString InFullDateTimePattern, const FString InLongDatePattern, const FString InLongTimePattern, const FString InMonthDayPattern, const FString InRFC1123Pattern, const FString InShortDatePattern, const FString InShortTimePattern, const FString InSortableDateTimePattern, const FString InUniversalSortableDateTimePattern, const FString InYearMonthPattern)
		: AbbreviatedDayNames(InAbbreviatedDayNames)
		, AbbreviatedMonthNames(InAbbreviatedMonthNames)
		, DayNames(InDayNames)
		, MonthNames(InMonthNames)
		, ShortestDayNames(InShortestDayNames)
		, AMDesignator(InAMDesignator)
		, DateSeparator(InDateSeparator)
		, TimeSeparator(InTimeSeparator)
		, FirstDayOfWeek(InFirstDayOfWeek)
		, FullDateTimePattern(InFullDateTimePattern)
		, LongDatePattern(InLongDatePattern)
		, LongTimePattern(InLongTimePattern)
		, MonthDayPattern(InMonthDayPattern)
		, PMDesignator(InPMDesignator)
		, RFC1123Pattern(InRFC1123Pattern)
		, ShortDatePattern(InShortDatePattern)
		, ShortTimePattern(InShortTimePattern)
		, SortableDateTimePattern(InSortableDateTimePattern)
		, UniversalSortableDateTimePattern(InUniversalSortableDateTimePattern)
		, YearMonthPattern(InYearMonthPattern)
	{ }

protected:
	// array of abbreviated names for the days of the week
	const TArray<FString> AbbreviatedDayNames;

	// array of abbreviated names for the months
	const TArray<FString> AbbreviatedMonthNames;

	// array of names for the days of the week
	const TArray<FString> DayNames;

	// Array of the names of the months
	const TArray<FString> MonthNames;

	// Array of the shortest abbreviations of the name of the days
	const TArray<FString> ShortestDayNames;

	// string designator for hours between 0:00:00 and 11:59:59
	const FString AMDesignator;

	// the character used to separate the date components of day, month, and year
	const FString DateSeparator;

	// the character used to separate the time components of seconds, minutes and hours
	const FString TimeSeparator;

	// The first day of the week @todo is this an index into DayNames, should the values of the arrays of DayNames and AbbreviatedDayNames be common ordered between cultures?
	const int FirstDayOfWeek;

	// Pattern to use for a long date and time
	const FString FullDateTimePattern;

	// Pattern to use for a long dates
	const FString LongDatePattern;

	// Pattern to use for a long times
	const FString LongTimePattern;

	// Pattern to use for month and day value
	const FString MonthDayPattern;

	// string designator for hours between 12:00:00 and 23:59:59 in non-24 hour display
	const FString PMDesignator;

	// Pattern to use for the Request for Comments (RFC) 1123 specification
	const FString RFC1123Pattern;

	// Pattern to use for a short dates
	const FString ShortDatePattern;

	// Pattern to use for a short times
	const FString ShortTimePattern;

	// Pattern to use for a date time which can be sorted
	const FString SortableDateTimePattern;

	// Pattern to use for a universal date time which can be sorted
	const FString UniversalSortableDateTimePattern;

	// Pattern to use for a year month.
	const FString YearMonthPattern;

	// @todo Pretty sure we'll need the genitive names of the months.

	// @todo Need static InvariantInfo? CurrentInfo?

};
	// @todo do we need a calendar class
	//Calendar
	//CalendarWeekRule
	//NativeCalendarName

redpajama_set_name: RedPajamaGithub


text:
package com.stulsoft.pconfig;

import com.typesafe.config.ConfigBeanFactory;
import com.typesafe.config.ConfigFactory;

/**
 * @author Yuriy Stul
 */
public class UseTestBean {
    public static void main(String[] args) {
        System.out.println("==>main");
        com.typesafe.config.Config c = ConfigFactory.load("array.conf");
        c.getConfig("test")
                .getConfigList("testList")
                .forEach(config -> {
                    TestBean tb = ConfigBeanFactory.create(config, TestBean.class);
                    System.out.println(tb);
                    System.out.printf("p1 = %d, p2: %s\n", tb.getP1(),tb.getP2());
                });
        System.out.println("<==main");
    }
}


text:
package org.onetwo.ext.permission;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;

import javax.annotation.Resource;

import org.onetwo.common.annotation.AnnotationUtils;
import org.onetwo.common.exception.BaseException;
import org.onetwo.common.expr.ExpressionFacotry;
import org.onetwo.common.log.JFishLoggerFactory;
import org.onetwo.common.utils.StringUtils;
import org.onetwo.ext.permission.api.IPermission;
import org.onetwo.ext.permission.api.annotation.ByPermissionClass;
import org.onetwo.ext.permission.utils.PermissionUtils;
import org.onetwo.ext.permission.utils.UrlResourceInfo;
import org.onetwo.ext.permission.utils.UrlResourceInfoParser;
import org.onetwo.ext.security.utils.SecurityConfig.ControllerPermissionNotFoundActions;
import org.onetwo.ext.security.utils.SecurityConfig.PermConfig;
import org.slf4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;

public class PermissionHandlerMappingListener implements InitializingBean {

	private UrlResourceInfoParser urlResourceInfoParser = new UrlResourceInfoParser();

	private final Logger logger = JFishLoggerFactory.getLogger(this.getClass());

	@Resource
	private PermissionManager<?> permissionManager;
	@Autowired
	private RequestMappingHandlerMapping requestMappingHandlerMapping;
//	private boolean syncPermissionData;
	private PermConfig permConfig;
	private Multimap<Method, IPermission> methodPermissionMapping = null;

	/*public void setSyncPermissionData(boolean syncMenuDataEnable) {
		this.syncPermissionData = syncMenuDataEnable;
	}*/

	@Override
	public void afterPropertiesSet() throws Exception {
		Assert.notNull(permConfig, "permConfig can not be null");

		if(!permConfig.isSync2db()){
			return ;
		}

		Map<RequestMappingInfo, HandlerMethod> handlerMethods = this.requestMappingHandlerMapping.getHandlerMethods();

		this.methodPermissionMapping = ArrayListMultimap.create(handlerMethods.size(), 3);

		this.onHandlerMethodsInitialized(handlerMethods);
		this.permissionManager.syncMenuToDatabase();

		this.permissionManager.setMethodPermissionMapping(methodPermissionMapping);
	}

	public void setPermConfig(PermConfig permConfig) {
		this.permConfig = permConfig;
	}

	private void setMenuUrlByRequestMappingInfo(Class<?> codeClass, IPermission perm, Entry<RequestMappingInfo, HandlerMethod> entry){
		IPermission menu = perm;

		Optional<RequestMethod> method = getFirstMethod(entry.getKey());
		if(method.isPresent() && RequestMethod.GET!=method.get()){
			return ;
		}

//		menu.setMethod(method);
		method.ifPresent(m->menu.setMethod(m.name()));
//		String url = entry.getKey().getPatternsCondition().getPatterns().iterator().next();
		String url = null;
		if(StringUtils.isNotBlank(menu.getUrl())){
			//如果自定义了,忽略自动解释
			url = menu.getUrl();
			menu.setUrl(url);
		}else{
			url = getFirstUrl(entry.getKey());
			if(!ExpressionFacotry.BRACE.isExpresstion(url)){
				menu.setUrl(url);
			}else{
				logger.info("url[{}] has brace, ignore.", url);
			}
		}
//		Iterator<RequestMethod> it = entry.getKey().getMethodsCondition().getMethods().iterator();

		/*if(it.hasNext()){
			//取第一个映射方法
			String method = entry.getKey().getMethodsCondition().getMethods().iterator().next().toString();
			menu.setMethod(method);
		}else{
			menu.setMethod(RequestMethod.GET.name());
		}*/
	}

	private void setResourcePatternByRequestMappingInfo(Class<?> codeClass, IPermission perm, Entry<RequestMappingInfo, HandlerMethod> entry){
		/*if(perm.getResourcesPattern()!=null){
			List<UrlResourceInfo> infos = urlResourceInfoParser.parseToUrlResourceInfos(perm.getResourcesPattern());
			//如果自定义了,忽略自动解释
			if(!infos.isEmpty()){
				String urls = this.urlResourceInfoParser.parseToString(infos);
				perm.setResourcesPattern(urls);
			}
			return ;
		}*/
		List<UrlResourceInfo> infos = urlResourceInfoParser.parseToUrlResourceInfos(perm.getResourcesPattern());

		Set<String> urlPattterns = entry.getKey().getPatternsCondition().getPatterns();

		if(urlPattterns.size()==1){
			String url = urlPattterns.stream().findFirst().orElse("");
			Optional<RequestMethod> method = getFirstMethod(entry.getKey());
			infos.add(new UrlResourceInfo(url, method.isPresent()?method.get().name():null));

		}else{
			//超过一个url映射的,不判断方法
			urlPattterns.stream().forEach(url->infos.add(new UrlResourceInfo(url)));
		}
		String urls = this.urlResourceInfoParser.parseToString(infos);
		perm.setResourcesPattern(urls);
	}

	/*private String appendStarPostfix(String url){
		url = StringUtils.trimEndWith(url, "/");
		if(!url.contains(".")){
			url += ".*";
		}
		return url;
	}*/

	private Optional<RequestMethod> getFirstMethod(RequestMappingInfo info){
		//取第一个映射方法
		return info.getMethodsCondition().getMethods().stream().findFirst();
	}

	private String getFirstUrl(RequestMappingInfo info){
		//取第一个映射地址
		return info.getPatternsCondition().getPatterns().stream().findFirst().orElse("");
	}

	public void onHandlerMethodsInitialized(Map<RequestMappingInfo, HandlerMethod> handlerMethods) {
		this.permissionManager.build();
		for(Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()){
			/*if (entry.getValue().getBeanType().getName().contains("SysSettingsController")) {
				System.out.println("test");
			}*/
			ByPermissionClass permClassInst = entry.getValue().getMethodAnnotation(ByPermissionClass.class);
			if(permClassInst==null){
				continue ;
			}
			for(Class<?> codeClass : permClassInst.value()){
				this.autoConifgPermission(codeClass, entry, permClassInst);
			}
		}
		this.permissionManager.getMemoryRootMenu().forEach(rootMenu->{
			logger.info("menu:\n{}", rootMenu.toTreeString("\n"));
		});
	}

	private void autoConifgPermission(Class<?> codeClass, Entry<RequestMappingInfo, HandlerMethod> entry, ByPermissionClass permClassInst){
		if(AnnotationUtils.findAnnotationWithDeclaring(codeClass, Deprecated.class)!=null){
			return;
		}
		IPermission perm = this.permissionManager.getPermission(codeClass);
		if(perm==null){
//			System.out.println("html: " + this.permissionManagerImpl.getMenuInfoParser().getRootMenu());
			String msg = String.format("can not find the menu code class[%s] in controller: %s. Maybe you forgot register the menu class!",
									codeClass, entry.getValue());
			if (permConfig.getPermissionNotFound()==ControllerPermissionNotFoundActions.THROWS) {
				throw new BaseException(msg);
			} else {
				logger.warn(msg);
				return ;
			}
		}
		if(PermissionUtils.isMenu(perm) && permClassInst.overrideMenuUrl()){
			this.setMenuUrlByRequestMappingInfo(codeClass, perm, entry);
		}
		this.setResourcePatternByRequestMappingInfo(codeClass, perm, entry);

//		String key = entry.getValue().getMethod().toString();
		this.methodPermissionMapping.put(entry.getValue().getMethod(), perm);
	}

}


text:
package org.robovm.samples.movieplayer.viewcontrollers;

import org.robovm.apple.coregraphics.CGPoint;
import org.robovm.apple.coregraphics.CGRect;
import org.robovm.apple.foundation.Foundation;
import org.robovm.apple.foundation.NSError;
import org.robovm.apple.foundation.NSNotificationCenter;
import org.robovm.apple.foundation.NSObject;
import org.robovm.apple.foundation.NSURL;
import org.robovm.apple.mediaplayer.MPMediaPlayback;
import org.robovm.apple.mediaplayer.MPMovieFinishReason;
import org.robovm.apple.mediaplayer.MPMovieLoadState;
import org.robovm.apple.mediaplayer.MPMoviePlaybackState;
import org.robovm.apple.mediaplayer.MPMoviePlayerController;
import org.robovm.apple.mediaplayer.MPMovieSourceType;
import org.robovm.apple.uikit.UIAlertView;
import org.robovm.apple.uikit.UIColor;
import org.robovm.apple.uikit.UIDevice;
import org.robovm.apple.uikit.UIImage;
import org.robovm.apple.uikit.UIImageView;
import org.robovm.apple.uikit.UIInterfaceOrientation;
import org.robovm.apple.uikit.UIRectEdge;
import org.robovm.apple.uikit.UIView;
import org.robovm.apple.uikit.UIViewController;
import org.robovm.objc.block.VoidBlock1;
import org.robovm.objc.block.VoidBlock3;
import org.robovm.samples.movieplayer.MoviePlayerUserPrefs;

public class MyMovieViewController extends UIViewController {
    private static final float MOVIE_VIEW_OFFSET_X = 20;
    private static final float MOVIE_VIEW_OFFSET_Y = 20;

    private final UIImageView movieBackgroundImageView;
    private final UIView backgroundView;
    private final MyOverlayViewController overlayController;
    private MPMoviePlayerController moviePlayerController;

    private NSObject observerLoadStateDidChange;
    private NSObject observerPlaybackDidFinish;
    private NSObject observerIsPreparedToPlayDidChange;
    private NSObject observerPlaybackStateDidChange;

    public MyMovieViewController () {
        movieBackgroundImageView = new UIImageView(UIImage.create("images/movieBackground.jpg"));
        movieBackgroundImageView.setFrame(new CGRect(0, 0, 240, 128));

        backgroundView = new UIView(new CGRect(0, 0, 320, 460));
        backgroundView.setBackgroundColor(UIColor.fromWhiteAlpha(0.66, 1));

        overlayController = new MyOverlayViewController(this);

        if (Integer.valueOf(UIDevice.getCurrentDevice().getSystemVersion().substring(0, 1)) >= 7) {
            setEdgesForExtendedLayout(UIRectEdge.None);
        }
    }

    /** Sent to the view controller after the user interface rotates. */
    @Override
    public void didRotate (UIInterfaceOrientation fromInterfaceOrientation) {
        if (moviePlayerController != null) {
            CGRect viewInsetRect = getView().getBounds().copy();
            moviePlayerController.getView().setFrame(viewInsetRect.inset(MOVIE_VIEW_OFFSET_X, MOVIE_VIEW_OFFSET_Y));
        }
        /* Size the overlay view for the current orientation. */
        resizeOverlayWindow();
    }

    @Override
    public boolean shouldAutorotate (UIInterfaceOrientation toInterfaceOrientation) {
        return true;
    }

    @Override
    public boolean canBecomeFirstResponder () {
        return true;
    }

    @Override
    protected void dispose (boolean finalizing) {
        deletePlayerAndNotificationObservers();
        super.dispose(finalizing);
    }

    /** Notifies the view controller that its view is about to be become visible. */
    @Override
    public void viewWillAppear (boolean animated) {
        super.viewWillAppear(animated);
        /* Size the overlay view for the current orientation. */
        resizeOverlayWindow();
        /* Update user settings for the movie (in case they changed). */
        applyUserSettings();
    }

    /** Notifies the view controller that its view is about to be dismissed, covered, or otherwise hidden from view. */
    @Override
    public void viewWillDisappear (boolean animated) {
        super.viewWillDisappear(animated);

        /* Remove the movie view from the current view hierarchy. */
        removeMovieViewFromViewHierarchy();
        /* Removie the overlay view. */
        removeOverlayView();
        /* Remove the background view. */
        backgroundView.removeFromSuperview();
        /* Delete the movie player object and remove the notification observers. */
        deletePlayerAndNotificationObservers();
    }

    /** Remove the movie view from the view hierarchy. */
    private void removeMovieViewFromViewHierarchy () {
        if (moviePlayerController != null) {
            moviePlayerController.getView().removeFromSuperview();
        }
    }

    private void displayError (NSError error) {
        if (error != null) {
            UIAlertView alert = new UIAlertView("Error", error.getLocalizedDescription(), null, "OK");
            alert.show();
        }
    }

    /** Add an overlay view on top of the movie. This view will display movie play states and includes a 'Close Movie' button. */
    protected void addOverlayView () {
        MPMoviePlayerController player = moviePlayerController;

        if (!(overlayController.getView().isDescendantOf(getView()) && player.getView().isDescendantOf(getView()))) {
            // add an overlay view to the window view hierarchy
            getView().addSubview(overlayController.getView());
        }
    }

    /** Remove overlay view from the view hierarchy. */
    private void removeOverlayView () {
        overlayController.getView().removeFromSuperview();
    }

    private void resizeOverlayWindow () {
        CGRect frame = overlayController.getView().getFrame();
        frame.setOrigin(new CGPoint(Math.round((getView().getFrame().getWidth() - frame.getWidth())) / 2.0, Math.round((getView()
            .getFrame().getHeight() - frame.getHeight()) / 2.0)));
        overlayController.getView().setFrame(frame);
    }

    /** Action method for the overlay view 'Close Movie' button. Remove the movie view and overlay view from the window, dispose
     * the movie object and remove the notification handlers. */
    public void closeOverlay () {
        moviePlayerController.stop();
        removeMovieViewFromViewHierarchy();
        removeOverlayView();
        backgroundView.removeFromSuperview();
        deletePlayerAndNotificationObservers();
    }

    /** Called by the MoviePlayerAppDelegate (UIApplicationDelegate protocol) applicationWillEnterForeground when the app is about
     * to enter the foreground. */
    public void willEnterForeground () {
        /*
         * Set the movie object settings (control mode, background color, and so on) in case these changed.
         */
        applyUserSettings();
    }

    /** Called soon after the Play Movie button is pressed to play the local movie. */
    protected void playMovieFile (NSURL movieFileURL) {
        createAndPlayMovie(movieFileURL, MPMovieSourceType.File);
    }

    /** Called soon after the Play Movie button is pressed to play the streaming movie. */
    protected void playMovieStream (NSURL movieFileURL) {
        MPMovieSourceType movieSourceType = MPMovieSourceType.Unknown;
        /* If we have a streaming url then specify the movie source type. */
        if (movieFileURL.getPathExtension().equals("m3u8")) {
            movieSourceType = MPMovieSourceType.Streaming;
        }
        createAndPlayMovie(movieFileURL, movieSourceType);
    }

    /** Create a MPMoviePlayerController movie object for the specified URL and add movie notification observers. Configure the
     * movie object for the source type, scaling mode, control style, background color, background image, repeat mode and AirPlay
     * mode. Add the view containing the movie content and controls to the existing view hierarchy. */
    private void createAndConfigurePlayer (NSURL movieURL, MPMovieSourceType sourceType) {
        /* Create a new movie player object. */
        MPMoviePlayerController player = new MPMoviePlayerController(movieURL);
        if (player != null) {
            /* Save the movie object. */
            moviePlayerController = player;
            /*
             * Register the current object as an observer for the movie notifications.
             */
            installMovieNotificationObservers();
            /* Specify the URL that points to the movie file. */
            player.setContentURL(movieURL);
            /*
             * If you specify the movie type before playing the movie it can result in faster load times.
             */
            player.setMovieSourceType(sourceType);
            /*
             * Apply the user movie preference settings to the movie player object.
             */
            applyUserSettings();
            /*
             * Add a background view as a subview to hide our other view controls underneath during movie playback.
             */
            getView().addSubview(backgroundView);
            /* Inset the movie frame in the parent view frame. */
            CGRect viewInsetRect = getView().getBounds().copy();
            viewInsetRect.inset(MOVIE_VIEW_OFFSET_X, MOVIE_VIEW_OFFSET_Y);
            player.getView().setFrame(viewInsetRect);
            player.getView().setBackgroundColor(UIColor.lightGray());
            /*
             * To present a movie in your application, incorporate the view contained in a movie player's view property into your
             * application's view hierarchy. Be sure to size the frame correctly.
             */
            getView().addSubview(player.getView());
        }
    }

    /** Load and play the specified movie url with the given file type. */
    private void createAndPlayMovie (NSURL movieURL, MPMovieSourceType sourceType) {
        createAndConfigurePlayer(movieURL, sourceType);
        /* Play the movie! */
        moviePlayerController.play();
    }

    /*
     * Apply user movie preference settings (these are set from the Settings: iPhone Settings->Movie Player) for scaling mode,
     * control style, background color, repeat mode, application audio session, background image and AirPlay mode.
     */
    private void applyUserSettings () {
        MPMoviePlayerController player = moviePlayerController;
        if (player != null) {
            player.setScalingMode(MoviePlayerUserPrefs.getScalingMode());
            player.setControlStyle(MoviePlayerUserPrefs.getControlStyle());
            player.getBackgroundView().setBackgroundColor(MoviePlayerUserPrefs.getBackgroundColor());
            player.setRepeatMode(MoviePlayerUserPrefs.getRepeatMode());
            if (MoviePlayerUserPrefs.useMovieBackground()) {
                movieBackgroundImageView.setFrame(getView().getBounds());
                player.getBackgroundView().addSubview(movieBackgroundImageView);
            } else {
                movieBackgroundImageView.removeFromSuperview();
            }
            /* Indicate the movie player allows AirPlay movie playback. */
            player.setAllowsAirPlay(true);
        }
    }

    /** Register observers for the various movie object notifications. */
    private void installMovieNotificationObservers () {
        observerLoadStateDidChange = MPMoviePlayerController.Notifications.observeLoadStateDidChange(moviePlayerController,
            new VoidBlock1<MPMoviePlayerController>() {
                @Override
                public void invoke (MPMoviePlayerController player) {
                    MPMovieLoadState loadState = player.getLoadState();
                    /* The load state is not known at this time. */
                    if (loadState.contains(MPMovieLoadState.Unknown)) {
                        overlayController.setLoadStateDisplayString("unknown");
                    }
                    /*
                     * The buffer has enough data that playback can begin, but it may run out of data before playback finishes.
                     */
                    if (loadState.contains(MPMovieLoadState.Playable)) {
                        overlayController.setLoadStateDisplayString("playable");
                    }
                    /*
                     * Enough data has been buffered for playback to continue uninterrupted.
                     */
                    if (loadState.contains(MPMovieLoadState.PlaythroughOK)) {
                        // Add an overlay view on top of the movie view
                        addOverlayView();
                        overlayController.setLoadStateDisplayString("playthrough ok");
                    }
                    /* The buffering of data has stalled. */
                    if (loadState.contains(MPMovieLoadState.Stalled)) {
                        overlayController.setLoadStateDisplayString("stalled");
                    }
                }
            });

        observerPlaybackDidFinish = MPMoviePlayerController.Notifications.observePlaybackDidFinish(moviePlayerController,
            new VoidBlock3<MPMoviePlayerController, MPMovieFinishReason, NSError>() {
                @Override
                public void invoke (MPMoviePlayerController player, MPMovieFinishReason reason, NSError error) {
                    switch (reason) {
                    /* The end of the movie was reached. */
                    case PlaybackEnded:
                        /*
                         * Add your code here to handle MPMovieFinishReasonPlaybackEnded.
                         */
                        break;
                    /* An error was encountered during playback. */
                    case PlaybackError:
                        Foundation.log("An error was encountered during playback");
                        displayError(error);
                        removeMovieViewFromViewHierarchy();
                        removeOverlayView();
                        backgroundView.removeFromSuperview();
                        break;
                    /* The user stopped playback. */
                    case UserExited:
                        removeMovieViewFromViewHierarchy();
                        removeOverlayView();
                        backgroundView.removeFromSuperview();
                        break;
                    default:
                        break;
                    }
                }
            });

        observerIsPreparedToPlayDidChange = MPMoviePlayerController.Notifications.observeIsPreparedToPlayDidChange(
            moviePlayerController, new VoidBlock1<MPMediaPlayback>() {
                @Override
                public void invoke (MPMediaPlayback player) {
                    addOverlayView();
                }
            });

        observerPlaybackStateDidChange = MPMoviePlayerController.Notifications.observePlaybackStateDidChange(
            moviePlayerController, new VoidBlock1<MPMoviePlayerController>() {
                @Override
                public void invoke (MPMoviePlayerController player) {
                    MPMoviePlaybackState playbackState = player.getPlaybackState();
                    /* Playback is currently stopped. */
                    if (playbackState == MPMoviePlaybackState.Stopped) {
                        overlayController.setPlaybackStateDisplayString("stopped");
                    }
                    /* Playback is currently under way. */
                    else if (playbackState == MPMoviePlaybackState.Playing) {
                        overlayController.setPlaybackStateDisplayString("playing");

                    }
                    /* Playback is currently paused. */
                    else if (playbackState == MPMoviePlaybackState.Paused) {
                        overlayController.setPlaybackStateDisplayString("paused");
                    }
                    /*
                     * Playback is temporarily interrupted, perhaps because the buffer ran out of content.
                     */
                    else if (playbackState == MPMoviePlaybackState.Interrupted) {
                        overlayController.setPlaybackStateDisplayString("interrupted");
                    }
                }
            });
    }

    /** Delete the movie player object, and remove the movie notification observers. */
    private void deletePlayerAndNotificationObservers () {
        removeMovieNotificationHandlers();
        moviePlayerController = null;
    }

    /** Remove the movie notification observers from the movie object. */
    private void removeMovieNotificationHandlers () {
        NSNotificationCenter.getDefaultCenter().removeObserver(observerLoadStateDidChange);
        NSNotificationCenter.getDefaultCenter().removeObserver(observerIsPreparedToPlayDidChange);
        NSNotificationCenter.getDefaultCenter().removeObserver(observerPlaybackDidFinish);
        NSNotificationCenter.getDefaultCenter().removeObserver(observerPlaybackStateDidChange);
    }
}


text:
require 'hyrax/ingest/runner'
require 'hyrax/ingest/has_report'
require 'hyrax/ingest/has_logger'
require 'hyrax/ingest/has_depositor'
require 'interloper'

module Hyrax
  module Ingest
    class BatchRunner
      include HasReport
      include HasLogger
      include HasDepositor
      include Interloper

      # Report before and after a batch is ingested.
      before(:run!) do
        logger.info "Starting batch ingest, batch size = #{iterations}."
        report.stat[:batch_size] = iterations
        report.stat[:datetime_started] = DateTime.now
      end

      after(:run!) do
        logger.info "Batch ingest complete."
        report.stat[:datetime_completed] = DateTime.now
        report.write_to_file
      end

      attr_reader :sip_paths

      def initialize(config_file_path:, sip_paths: [], shared_sip_path: nil, iterations: nil, depositor: nil)
        @sip_paths = sip_paths
        @shared_sip_path = shared_sip_path
        @config_file_path = config_file_path
        @iterations = iterations
        self.depositor = depositor
      end

      def run!
        runners.each { |runner| runner.run! }
      rescue StandardError => error
        # TODO: move to callback, but :rescue hook doesn't exist yet in
        # Interloper gem.
        report.stat[:datetime_completed] = DateTime.now
        report.failed_with error
        raise error
      ensure
        # TODO: move to callback, but :ensure hook doesn't exist yet in
        # Interloper gem.
        report.write_to_file
      end

      # Returns an array containing the IDs of new or updated records.
      # Currently only returns the IDs for ActiveFedora records (or
      # subclasses) that are specified at the top level (i.e. not nested) of
      # the ingest configuration.
      # @return [Array] list of IDs
      def ingested_ids
        ingested_ids_by_type.flatten
      end

      # Returns an hash containing the IDs of new or updated records, keyed by
      # the model class by which they were saved.
      # Example:
      #   { FileSet => ['123', '456'], Work => ['789'] }
      # Currently only returns the IDs for ActiveFedora records (or
      # subclasses) that are specified at the top level (i.e. not nested) of
      # the ingest configuration.
      # @return [Hash] IDs keyed by the model class by which they were saved.
      def ingested_ids_by_type
        {}.tap do |h|
          runners.each do |runner|
            runner.ingested_ids_by_type.each do |type, ids|
              h[type] ||= []
              h[type] += ids
              h[type].uniq!
            end
          end
        end
      end

      # Returns an array containing the IDs of new or updated records.
      # Currently only returns the IDs for ActiveFedora records (or
      # subclasses) that are specified at the top level (i.e. not nested) of
      # the ingest configuration.
      # @return [Array] list of IDs
      def ingested_ids
        ingested_ids_by_type.flatten
      end

      # Returns an hash containing the IDs of new or updated records, keyed by
      # the model class by which they were saved.
      # Example:
      #   { FileSet => ['123', '456'], Work => ['789'] }
      # Currently only returns the IDs for ActiveFedora records (or
      # subclasses) that are specified at the top level (i.e. not nested) of
      # the ingest configuration.
      # @return [Hash] IDs keyed by the model class by which they were saved.
      def ingested_ids_by_type
        {}.tap do |h|
          runners.each do |runner|
            runner.ingested_ids_by_type.each do |type, ids|
              h[type] ||= []
              h[type] += ids
              h[type].uniq!
            end
          end
        end
      end

      private

        def iterations
          # Return @iterations.to_i if it's not nil and not empty
          unless @iterations.nil? || @iterations.to_s.empty?
            @iterations
          else
            [1, @sip_paths.count].max
          end.to_i
        end

        def runners
          @runners ||= (0...iterations).map do |iteration|
            Hyrax::Ingest::Runner.new(config_file_path: @config_file_path, sip_path: @sip_paths[iteration], shared_sip_path: @shared_sip_path, iteration: iteration, depositor: depositor).tap do |runner|
              runner.report = report if runner.respond_to? :report=
            end
          end
        end
    end
  end
end


text:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.jenkins-ci.plugins</groupId>
    <artifactId>plugin</artifactId>
    <version>1.509</version>
  </parent>

  <groupId>com.cloudbees.jenkins.plugins</groupId>
  <artifactId>bees-sdk-plugin</artifactId>
  <version>1.3-SNAPSHOT</version>
  <packaging>hpi</packaging>

  <scm>
    <connection>scm:git:https://github.com/ndeloof/bees-sdk-plugin.git</connection>
    <developerConnection>scm:git:git@github.com:ndeloof/bees-sdk-plugin.git</developerConnection>
    <url>https://github.com/ndeloof/bees-sdk-plugin</url>
  </scm>

  <repositories>
    <repository>
      <id>repo.jenkins-ci.org</id>
      <url>http://repo.jenkins-ci.org/public/</url>
    </repository>
  </repositories>

  <pluginRepositories>
    <pluginRepository>
      <id>repo.jenkins-ci.org</id>
      <url>http://repo.jenkins-ci.org/public/</url>
    </pluginRepository>
  </pluginRepositories>

  <dependencies>
      <dependency>
          <groupId>com.cloudbees.jenkins.plugins</groupId>
          <artifactId>cloudbees-credentials</artifactId>
          <version>3.2</version>
      </dependency>
      <dependency>
          <groupId>com.cloudbees.jenkins.plugins</groupId>
          <artifactId>cloudbees-registration</artifactId>
          <version>3.11</version>
          <optional>true</optional>
      </dependency>
  </dependencies>

  <properties>
    <!--
      explicitly specifying the latest version here because one we get from the parent POM
      tends to lag behind a bit
    -->
    <maven-hpi-plugin.version>1.96</maven-hpi-plugin.version>
  </properties>
</project>


text:
import numpy as np
import pandas as pd

from xray import DataArray

import xray.plot as xplt
from xray.plot.plot import (_infer_interval_breaks,
                            _determine_cmap_params)

from . import TestCase, requires_matplotlib

try:
    import matplotlib as mpl
    # Using a different backend makes Travis CI work.
    mpl.use('Agg')
    # Order of imports is important here.
    import matplotlib.pyplot as plt
except ImportError:
    pass

@requires_matplotlib
class PlotTestCase(TestCase):

    def tearDown(self):
        # Remove all matplotlib figures
        plt.close('all')

    def pass_in_axis(self, plotmethod):
        fig, axes = plt.subplots(ncols=2)
        plotmethod(ax=axes[0])
        self.assertTrue(axes[0].has_data())

    def imshow_called(self, plotmethod):
        plotmethod()
        images = plt.gca().findobj(mpl.image.AxesImage)
        return len(images) > 0

    def contourf_called(self, plotmethod):
        plotmethod()
        paths = plt.gca().findobj(mpl.collections.PathCollection)
        return len(paths) > 0

class TestPlot(PlotTestCase):

    def setUp(self):
        self.darray = DataArray(np.random.randn(2, 3, 4))

    def test1d(self):
        self.darray[:, 0, 0].plot()

    def test2d_uniform_calls_imshow(self):
        self.assertTrue(self.imshow_called(self.darray[:, :, 0].plot))

    def test2d_nonuniform_calls_contourf(self):
        a = self.darray[:, :, 0]
        a.coords['dim_1'] = [2, 1, 89]
        self.assertTrue(self.contourf_called(a.plot))

    def test3d(self):
        self.darray.plot()

    def test_can_pass_in_axis(self):
        self.pass_in_axis(self.darray.plot)

    def test__infer_interval_breaks(self):
        self.assertArrayEqual([-0.5, 0.5, 1.5], _infer_interval_breaks([0, 1]))
        self.assertArrayEqual([-0.5, 0.5, 5.0, 9.5, 10.5],
                              _infer_interval_breaks([0, 1, 9, 10]))
        self.assertArrayEqual(pd.date_range('20000101', periods=4) - np.timedelta64(12, 'h'),
                              _infer_interval_breaks(pd.date_range('20000101', periods=3)))

class TestPlot1D(PlotTestCase):

    def setUp(self):
        d = [0, 1.1, 0, 2]
        self.darray = DataArray(d, coords={'period': range(len(d))})

    def test_xlabel_is_index_name(self):
        self.darray.plot()
        self.assertEqual('period', plt.gca().get_xlabel())

    def test_no_label_name_on_y_axis(self):
        self.darray.plot()
        self.assertEqual('', plt.gca().get_ylabel())

    def test_ylabel_is_data_name(self):
        self.darray.name = 'temperature'
        self.darray.plot()
        self.assertEqual(self.darray.name, plt.gca().get_ylabel())

    def test_wrong_dims_raises_valueerror(self):
        twodims = DataArray(np.arange(10).reshape(2, 5))
        with self.assertRaises(ValueError):
            twodims.plot.line()

    def test_format_string(self):
        self.darray.plot.line('ro')

    def test_can_pass_in_axis(self):
        self.pass_in_axis(self.darray.plot.line)

    def test_nonnumeric_index_raises_typeerror(self):
        a = DataArray([1, 2, 3], {'letter': ['a', 'b', 'c']})
        with self.assertRaisesRegexp(TypeError, r'[Pp]lot'):
            a.plot.line()

    def test_primitive_returned(self):
        p = self.darray.plot.line()
        self.assertTrue(isinstance(p[0], mpl.lines.Line2D))

    def test_plot_nans(self):
        self.darray[1] = np.nan
        self.darray.plot.line()

    def test_x_ticks_are_rotated_for_time(self):
        time = pd.date_range('2000-01-01', '2000-01-10')
        a = DataArray(np.arange(len(time)), {'t': time})
        a.plot.line()
        rotation = plt.gca().get_xticklabels()[0].get_rotation()
        self.assertFalse(rotation == 0)

class TestPlotHistogram(PlotTestCase):

    def setUp(self):
        self.darray = DataArray(np.random.randn(2, 3, 4))

    def test_3d_array(self):
        self.darray.plot.hist()

    def test_title_no_name(self):
        self.darray.plot.hist()
        self.assertEqual('', plt.gca().get_title())

    def test_title_uses_name(self):
        self.darray.name = 'randompoints'
        self.darray.plot.hist()
        self.assertIn(self.darray.name, plt.gca().get_title())

    def test_ylabel_is_count(self):
        self.darray.plot.hist()
        self.assertEqual('Count', plt.gca().get_ylabel())

    def test_can_pass_in_kwargs(self):
        nbins = 5
        self.darray.plot.hist(bins=nbins)
        self.assertEqual(nbins, len(plt.gca().patches))

    def test_can_pass_in_axis(self):
        self.pass_in_axis(self.darray.plot.hist)

    def test_primitive_returned(self):
        h = self.darray.plot.hist()
        self.assertTrue(isinstance(h[-1][0], mpl.patches.Rectangle))

    def test_plot_nans(self):
        self.darray[0, 0, 0] = np.nan
        self.darray.plot.hist()

@requires_matplotlib
class TestDetermineCmapParams(TestCase):
    def test_robust(self):
        data = np.random.RandomState(1).rand(100)
        vmin, vmax, cmap, extend = _determine_cmap_params(data, robust=True)
        self.assertEqual(vmin, np.percentile(data, 2))
        self.assertEqual(vmax, np.percentile(data, 98))
        self.assertEqual(cmap.name, 'viridis')
        self.assertEqual(extend, 'both')

    def test_center(self):
        data = np.random.RandomState(2).rand(100)
        vmin, vmax, cmap, extend = _determine_cmap_params(data, center=0.5)
        self.assertEqual(vmax - 0.5, 0.5 - vmin)
        self.assertEqual(cmap, 'RdBu_r')
        self.assertEqual(extend, 'neither')

class Common2dMixin:
    """
    Common tests for 2d plotting go here.

    These tests assume that a staticmethod for `self.plotfunc` exists.
    Should have the same name as the method.
    """
    def setUp(self):
        rs = np.random.RandomState(123)
        self.darray = DataArray(rs.randn(10, 15), dims=['y', 'x'])
        self.plotmethod = getattr(self.darray.plot, self.plotfunc.__name__)

    def test_label_names(self):
        self.plotmethod()
        self.assertEqual('x', plt.gca().get_xlabel())
        self.assertEqual('y', plt.gca().get_ylabel())

    def test_1d_raises_valueerror(self):
        with self.assertRaisesRegexp(ValueError, r'[Dd]im'):
            self.plotfunc(self.darray[0, :])

    def test_3d_raises_valueerror(self):
        a = DataArray(np.random.randn(2, 3, 4))
        with self.assertRaisesRegexp(ValueError, r'[Dd]im'):
            self.plotfunc(a)

    def test_nonnumeric_index_raises_typeerror(self):
        a = DataArray(np.random.randn(3, 2),
                      coords=[['a', 'b', 'c'], ['d', 'e']])
        with self.assertRaisesRegexp(TypeError, r'[Pp]lot'):
            self.plotfunc(a)

    def test_can_pass_in_axis(self):
        self.pass_in_axis(self.plotmethod)

    def test_xyincrease_false_changes_axes(self):
        self.plotmethod(xincrease=False, yincrease=False)
        xlim = plt.gca().get_xlim()
        ylim = plt.gca().get_ylim()
        diffs = xlim[0] - 14, xlim[1] - 0, ylim[0] - 9, ylim[1] - 0
        self.assertTrue(all(abs(x) < 1 for x in diffs))

    def test_xyincrease_true_changes_axes(self):
        self.plotmethod(xincrease=True, yincrease=True)
        xlim = plt.gca().get_xlim()
        ylim = plt.gca().get_ylim()
        diffs = xlim[0] - 0, xlim[1] - 14, ylim[0] - 0, ylim[1] - 9
        self.assertTrue(all(abs(x) < 1 for x in diffs))

    def test_plot_nans(self):
        x1 = self.darray[:5]
        x2 = self.darray.copy()
        x2[5:] = np.nan

        clim1 = self.plotfunc(x1).get_clim()
        clim2 = self.plotfunc(x2).get_clim()
        self.assertEqual(clim1, clim2)

    def test_viridis_cmap(self):
        cmap_name = self.plotmethod(cmap='viridis').get_cmap().name
        self.assertEqual('viridis', cmap_name)

    def test_default_cmap(self):
        cmap_name = self.plotmethod().get_cmap().name
        self.assertEqual('RdBu_r', cmap_name)

        cmap_name = self.plotfunc(abs(self.darray)).get_cmap().name
        self.assertEqual('viridis', cmap_name)

    def test_can_change_default_cmap(self):
        cmap_name = self.plotmethod(cmap='jet').get_cmap().name
        self.assertEqual('jet', cmap_name)

    def test_diverging_color_limits(self):
        artist = self.plotmethod()
        vmin, vmax = artist.get_clim()
        self.assertAlmostEqual(-vmin, vmax)

class TestContourf(Common2dMixin, PlotTestCase):

    plotfunc = staticmethod(xplt.contourf)

    def test_contourf_called(self):
        # Having both statements ensures the test works properly
        self.assertFalse(self.contourf_called(self.darray.plot.imshow))
        self.assertTrue(self.contourf_called(self.darray.plot.contourf))

    def test_primitive_artist_returned(self):
        artist = self.plotmethod()
        self.assertTrue(isinstance(artist, mpl.contour.QuadContourSet))

    def test_extend(self):
        artist = self.plotmethod()
        self.assertEqual(artist.extend, 'neither')

        artist = self.plotmethod(robust=True)
        self.assertEqual(artist.extend, 'both')

        artist = self.plotmethod(vmin=-0, vmax=10)
        self.assertEqual(artist.extend, 'min')

        artist = self.plotmethod(vmin=-10, vmax=0)
        self.assertEqual(artist.extend, 'max')

class TestContour(Common2dMixin, PlotTestCase):

    plotfunc = staticmethod(xplt.contour)

class TestPcolormesh(Common2dMixin, PlotTestCase):

    plotfunc = staticmethod(xplt.pcolormesh)

    def test_primitive_artist_returned(self):
        artist = self.plotmethod()
        self.assertTrue(isinstance(artist, mpl.collections.QuadMesh))

    def test_everything_plotted(self):
        artist = self.plotmethod()
        self.assertEqual(artist.get_array().size, self.darray.size)

class TestImshow(Common2dMixin, PlotTestCase):

    plotfunc = staticmethod(xplt.imshow)

    def test_imshow_called(self):
        # Having both statements ensures the test works properly
        self.assertFalse(self.imshow_called(self.darray.plot.contourf))
        self.assertTrue(self.imshow_called(self.darray.plot.imshow))

    def test_xy_pixel_centered(self):
        self.darray.plot.imshow()
        self.assertTrue(np.allclose([-0.5, 14.5], plt.gca().get_xlim()))
        self.assertTrue(np.allclose([9.5, -0.5], plt.gca().get_ylim()))

    def test_default_aspect_is_auto(self):
        self.darray.plot.imshow()
        self.assertEqual('auto', plt.gca().get_aspect())

    def test_can_change_aspect(self):
        self.darray.plot.imshow(aspect='equal')
        self.assertEqual('equal', plt.gca().get_aspect())

    def test_primitive_artist_returned(self):
        artist = self.plotmethod()
        self.assertTrue(isinstance(artist, mpl.image.AxesImage))


text:
package cherry.goods.crypto;

import java.util.Map;

import cherry.goods.crypto.VersionStrategy.VersionedData;

public class VersionedSignature implements Signature {

	private Integer defaultVersion;

	private Map<Integer, Signature> signatureMap;

	private VersionStrategy<byte[], Integer> versionStrategy = new DefaultVersionStrategy();

	public void setDefaultVersion(Integer defaultVersion) {
		this.defaultVersion = defaultVersion;
	}

	public void setSignatureMap(Map<Integer, Signature> signatureMap) {
		this.signatureMap = signatureMap;
	}

	public void setVersionStrategy(VersionStrategy<byte[], Integer> versionStrategy) {
		this.versionStrategy = versionStrategy;
	}

	@Override
	public byte[] sign(byte[] in) {
		Signature signature = signatureMap.get(defaultVersion);
		if (signature == null) {
			throw new IllegalStateException("No matching Signature for version " + defaultVersion);
		}
		byte[] b = signature.sign(in);
		return versionStrategy.encode(b, defaultVersion);
	}

	@Override
	public boolean verify(byte[] in, byte[] signed) {
		VersionedData<byte[], Integer> vd = versionStrategy.decode(signed);
		Signature signature = signatureMap.get(vd.getVersion());
		if (signature == null) {
			throw new IllegalStateException("No matching Signature for version " + vd.getVersion());
		}
		return signature.verify(in, vd.getData());
	}

}


text:
package com.justep.system.component;

import java.util.Map;
import java.util.UUID;

import org.dom4j.Element;

import com.justep.ui.component.ComponentTemplate;

public class List implements ComponentTemplate{
	protected Element eDef;
	//private Map<String, Object> context;
	protected String foreachFuncName;
	protected String foreachAfterRenderFuncName;

	public void execute(Element bound, Map<String, String> dataItems, Map<String, Object> props, Map<String, String> events,
			Map<String, Object> context) {
		eDef = bound;
		//this.context = context;
		String xid = eDef.attributeValue("xid");
		if(null==xid || "".equals(xid)){
			xid = UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");
			eDef.addAttribute("xid", xid);
		}
		foreachFuncName = "$model.foreach_"+xid;
		foreachAfterRenderFuncName = "$model.foreach_afterRender_"+xid;

		processElement();
	}

	protected String getForeachFuncName() {
		return foreachFuncName+"($element)";
	}

	protected String getForeachAfterRenderFuncName() {
		return foreachAfterRenderFuncName+".bind($model,$element)";
	}

	protected Element getTemplate(){
		return (Element)eDef.selectSingleNode(".//*[contains(@class,'x-list-template')]");
	}

	protected void processElement(){
		Element eT = getTemplate();

		if(null!=eT){
			addClass(eT, "hide");
			String data = eDef.attributeValue("data");
			if(null!=data && !"".equals(data)){
				eT.addAttribute("bind-foreach", "{data:"+getForeachFuncName()+",afterRender:"+getForeachAfterRenderFuncName()+"}");
			}
		}
	}

	protected void addClass(Element ele, String sClass){
		if(null!=ele){
			String clz = ele.attributeValue("class");
			if(null!=clz && !"".equals(clz))
				ele.addAttribute("class", clz+" "+sClass);
			else ele.addAttribute("class", sClass);
		}
	}
}


text:
.. _deployment:

Deployment
==========

Deploying Cob applications is easy and straightforward. Cob uses Docker for deployment -- it helps you build a dockerized version of your app, which you can then push to a repository or deploy directly to the local machine.

Deployment Requirements
-----------------------

.. _deployment_deps:

Cob has several requirements in order to be successfully deployed on your system/machine.

Python Version
~~~~~~~~~~~~~~

Cob requires Python 3.6 or newer in order to install and run correctly. If you are deploying on Ubuntu 18.04 or newer, this should already be the case for your system.

For Ubuntu 16.04 or older, it is recommended to use the *deadsnakes* PPA for installing 3.6::

  $ sudo apt-get install -y software-properties-common
  $ sudo add-apt-repository ppa:deadsnakes/ppa
  $ sudo apt-get update
  $ sudo apt-get install -y python3.6

Docker and Docker-Compose
~~~~~~~~~~~~~~~~~~~~~~~~~

Deploying a cob app requires *docker* to be installed. In addition, ``docker-compose`` is needed.

.. note:: In some cases docker-compose is bundled with ``docker`` on your platform. However, due to a compatibility issue of the docker-compose format, Cob requires version 1.13 and above, which might not be the case for your installation.

          In any case, it is recommended to follow the `official guide <https://docs.docker.com/compose/install/>`_ for setting up ``docker-compose``.

Building a Docker Image
-----------------------

First, you'll need to build the Docker image for your project. This is done by running::

  $ cob docker build

This command builds a docker image labeled ``<your project name>>:dev`` by default. This means that if your project is named "todos",
the image would be named ``todos:dev``.

Testing Dockerized Apps
-----------------------

To make sure no new issues get introduced as a result of packaging your app through Docker, you can run your tests
inside the docker containers comprising your app, meaning it will run very similarly to how it would run in production.

This is done by running ``cob docker test``.

Tagging and Pushing Images
--------------------------

In most cases you would probably like to tag your released images and upload them to a Docker registry. This can be done by setting the *image name* for your project before building images.

Under ``.cob-project.yml``, add the ``docker.image_name`` configuration::

  # .cob-project.yml
  ...
  docker:
      image_name: "your.server.com:4567/myproject"

Now when you build or test your project, the docker image created will be ``your.server.com:4567/myproject:dev``

Once you're satisfied with a built image, you can tag it directly through docker as your "latest" version::

  $ cob docker tag-latest

Then you can push your image to the repository with a standard ``docker push`` command::

  $ cob docker push

.. note:: both ``cob docker tag-latest`` and ``cob docker push`` take the image name from the project's configuration, and are intended as shortcuts for ``docker tag`` and ``docker push``.

Deploying on Systemd-based Systems
----------------------------------

If your target machine is based on *systemd* (e.g. recent Ubuntu Server releases, CentOS 7.x etc.), you can deploy a dockerized cob project by running::

  $ cob docker deploy your.server.com:4567/myproject:latest

This will pull off the needed information from the Docker image and create appropriate unit files to run your project.

.. note:: cob uses docker-compose for deployment. a docker-compose-override yml file can be provided which is then used as described in `docker-compose overview <https://docs.docker.com/compose/reference/overview/>`_.

To use the above capability, add ``--compose-override <full path to override file>`` to the above ``cob docker deploy`` command.
You can use more than one compose-override files by repeating the flag for each file.


text:
/*
El atributo ABIERTO y el APTODISCAPACIDAD deben ser 1 o 0
*/

/*
Aqui cumplen
*/
INSERT INTO ZONA VALUES ('ZONA BRASIL', 100, 1, 0, 'Zona bonita');

/*
Aqui no cumple ABIERTO
*/
INSERT INTO ZONA VALUES ('ZONA COLOMBIA', 100, 4, 0, 'Zona bonita');
/*
Aqui no cumple APTODISCAPACIDAD
*/
INSERT INTO ZONA VALUES ('ZONA ECUADOR', 100, 1, 5, 'Zona bonita');

/*
Se borra
*/
DELETE FROM ZONA WHERE NOMBRE = 'ZONA BRASIL';


text:
* `docker-compose up -d` - reads docker-compose.yml and deploys containers
* `docker-compose ps` - list docker containers and their status
* `docker-compose run web` - run an individual container (good for debugging as the errors are output)
* `docker-compose stop` - stop all containers
* `docker-compose pull` - re-pull all containers from the registry (checking for updates)
* `docker-compose run --entrypoint ls web /etc/nginx/sites-available` - run a specific command in container, not the standard entrypoint (process)
* `docker inspect --format '{{ .NetworkSettings.IPAddress }}' data_db_1` - get IP address of a container

### vagrant handy commands
* `vagrant ssh` - log into vagrantbox

### boot2docker handy commands
* `boot2docker up` - start docker host vm
* `boot2docker down` - stop docker host vm
* `boot2docker ssh 'ls -l /data/vhosts/nginx/*.conf'` - execute a command in the host vm
* `VBoxManage sharedfolder add boot2docker-vm --name spira --hostpath ~/sites/spira/spira` - add a shared folder (path to your repo) to the host vm. The name is used for mounting the volume
* `VBoxManage setextradata boot2docker-vm VBoxInternal2/SharedFoldersEnableSymlinksCreate/spira 1` - allow symlinking within the shared volume
* `boot2docker ssh 'sudo mount -t vboxsf -o uid=1000,gid=50 spira /data'` - mount volume on the host vm (the name must match the shared folder)
* `boot2docker ssh 'ls -l /data'` - verify mounting in boot2docker
* `VBoxManage modifyvm boot2docker-vm --natpf1 "api,tcp,,8080,,8080"` - open a port on the host vm
* `VBoxManage modifyvm "boot2docker-vm" --natpf1 delete "xdebug"` - close opened port
* `VBoxManage modifyvm boot2docker-vm --memory 4000` - allocate more ram to the machine (unit is MB)

### Container development (only available from within the spira vagrant box if you place docker source repos in a folder (../../docker) relative to this README.md file.
* `docker build -t spira/docker-phpfpm:latest .` - build an image, give it a tag. Ensure you are in the folder containing the 'Dockerfile' that you want to build
* `docker push spira/docker-phpfpm` - publish a container back to dockerhub (feel free to halt the process after the first image uploads, the process continues in the background). Also note that unless pushing to a private hub, you are better off not pushing from local, and use [Docker Hub's Automated Builds](https://docs.docker.com/docker-hub/builds/) instead.
* `docker images -q --filter "dangling=true" | xargs docker rmi` - delete all images that are not current (free up some disk space)
* Getting resolve issues when building? Edit `/etc/resolve.conf` in boot2docker. (`boot2docker ssh` then `vi /etc/resolve.conf` to edit) and change the nameserver entry: `nameserver 8.8.8.8`


text:
layout: default
title: The server
---

# The server

All the Glide configuration is managed through a central object called the `Server`. This includes the image [source location](/config/source-and-cache/) (where the original images are saved), the image [cache location](/config/source-and-cache/) (where the manipulated images are saved), the image manipulation API as well as any configuration options.

## Setup with factory

The easiest way to configure the `Server` is using the supplied factory.

~~~ php
<?php

$server = League\Glide\ServerFactory::create([
    'source' => 'path/to/source/folder',
    'cache' => 'path/to/cache/folder',
]);
~~~

## Setup manually

You can also choose to instantiate the `Server` object manually. This allows finer control over what dependencies are being used. For example, if you wanted to add additional functionality to the API, you could load custom manipulators in addition to those provided with Glide.

~~~ php
<?php

// Set image source
$source = new League\Flysystem\Filesystem(
    new League\Flysystem\Adapter\Local('path/to/source/folder')
);

// Set image cache
$cache = new League\Flysystem\Filesystem(
    new League\Flysystem\Adapter\Local('path/to/cache/folder')
);

// Set image manager
$imageManager = new Intervention\Image\ImageManager([
    'driver' => 'imagick',
]);

// Set manipulators
$manipulators = [
    new League\Glide\Api\Manipulator\Orientation(),
    new League\Glide\Api\Manipulator\Rectangle(),
    new League\Glide\Api\Manipulator\Size(2000*2000),
    new League\Glide\Api\Manipulator\Brightness(),
    new League\Glide\Api\Manipulator\Contrast(),
    new League\Glide\Api\Manipulator\Gamma(),
    new League\Glide\Api\Manipulator\Sharpen(),
    new League\Glide\Api\Manipulator\Filter(),
    new League\Glide\Api\Manipulator\Blur(),
    new League\Glide\Api\Manipulator\Pixelate(),
    new League\Glide\Api\Manipulator\Output(),
];

// Set API
$api = new League\Glide\Api\Api($imageManager, $manipulators);

// Setup Glide server
$server = new League\Glide\Server($source, $cache, $api);
~~~