text:
<?php
/**
 * LeftAndMain is the parent class of all the two-pane views in the CMS.
 * If you are wanting to add more areas to the CMS, you can do it by subclassing LeftAndMain.
 *
 * This is essentially an abstract class which should be subclassed.
 * See {@link CMSMain} for a good example.
 *
 * @package framework
 * @subpackage admin
 */
class LeftAndMain extends Controller implements PermissionProvider {

	/**
	 * The 'base' url for CMS administration areas.
	 * Note that if this is changed, many javascript
	 * behaviours need to be updated with the correct url
	 *
	 * @config
	 * @var string $url_base
	 */
	private static $url_base = "admin";

	/**
	 * The current url segment attached to the LeftAndMain instance
	 *
	 * @config
	 * @var string
	 */
	private static $url_segment;

	/**
	 * @config
	 * @var string
	 */
	private static $url_rule = '/$Action/$ID/$OtherID';

	/**
	 * @config
	 * @var string
	 */
	private static $menu_title;

	/**
	 * @config
	 * @var string
	 */
	private static $menu_icon;

	/**
	 * @config
	 * @var int
	 */
	private static $menu_priority = 0;

	/**
	 * @config
	 * @var int
	 */
	private static $url_priority = 50;

	/**
	 * A subclass of {@link DataObject}.
	 *
	 * Determines what is managed in this interface, through
	 * {@link getEditForm()} and other logic.
	 *
	 * @config
	 * @var string
	 */
	private static $tree_class = null;

	/**
	 * The url used for the link in the Help tab in the backend
	 *
	 * @config
	 * @var string
	 */
	private static $help_link = 'http://userhelp.silverstripe.org/en/3.2/';

	/**
	 * @var array
	 */
	private static $allowed_actions = array(
		'index',
		'save',
		'savetreenode',
		'getsubtree',
		'updatetreenodes',
		'printable',
		'show',
		'EditorToolbar',
		'EditForm',
		'AddForm',
		'batchactions',
		'BatchActionsForm',
	);

	/**
	 * @config
	 * @var Array Codes which are required from the current user to view this controller.
	 * If multiple codes are provided, all of them are required.
	 * All CMS controllers require "CMS_ACCESS_LeftAndMain" as a baseline check,
	 * and fall back to "CMS_ACCESS_<class>" if no permissions are defined here.
	 * See {@link canView()} for more details on permission checks.
	 */
	private static $required_permission_codes;

	/**
	 * @config
	 * @var String Namespace for session info, e.g. current record.
	 * Defaults to the current class name, but can be amended to share a namespace in case
	 * controllers are logically bundled together, and mainly separated
	 * to achieve more flexible templating.
	 */
	private static $session_namespace;

	/**
	 * Register additional requirements through the {@link Requirements} class.
	 * Used mainly to work around the missing "lazy loading" functionality
	 * for getting css/javascript required after an ajax-call (e.g. loading the editform).
	 *
	 * YAML configuration example:
	 *
	 * LeftAndMain:
	 *   extra_requirements_javascript:
	 *     mysite/javascript/myscript.js:
	 *
	 *
	 * @config
	 * @var array
	 */
	private static $extra_requirements_javascript = array();

	/**
	 * YAML configuration example:
	 *
	 * LeftAndMain:
	 *   extra_requirements_css:
	 *     mysite/css/mystyle.css:
	 *       media: screen
	 *
	 *
	 * @config
	 * @var array See {@link extra_requirements_javascript}
	 */
	private static $extra_requirements_css = array();

	/**
	 * @config
	 * @var array See {@link extra_requirements_javascript}
	 */
	private static $extra_requirements_themedCss = array();

	/**
	 * If true, call a keepalive ping every 5 minutes from the CMS interface,
	 * to ensure that the session never dies.
	 *
	 * @config
	 * @var boolean
	 */
	private static $session_keepalive_ping = true;

	/**
	 * @var PjaxResponseNegotiator
	 */
	protected $responseNegotiator;

	/**
	 * @param Member $member
	 * @return boolean
	 */
	public function canView($member = null) {
		if(!$member && $member !== FALSE) $member = Member::currentUser();

		// cms menus only for logged-in members
		if(!$member) return false;

		// alternative extended checks
		if($this->hasMethod('alternateAccessCheck')) {
			$alternateAllowed = $this->alternateAccessCheck();
			if($alternateAllowed === FALSE) return false;
		}

		// Check for "CMS admin" permission
		if(Permission::checkMember($member, "CMS_ACCESS_LeftAndMain")) return true;

		// Check for LeftAndMain sub-class permissions
		$codes = array();
		$extraCodes = $this->stat('required_permission_codes');
		if($extraCodes !== false) { // allow explicit FALSE to disable subclass check
			if($extraCodes) $codes = array_merge($codes, (array)$extraCodes);
			else $codes[] = "CMS_ACCESS_$this->class";
		}
		foreach($codes as $code) if(!Permission::checkMember($member, $code)) return false;

		return true;
	}

	/**
	 * @uses LeftAndMainExtension->init()
	 * @uses LeftAndMainExtension->accessedCMS()
	 * @uses CMSMenu
	 */
	public function init() {
		parent::init();

		Config::inst()->update('SSViewer', 'rewrite_hash_links', false);
		Config::inst()->update('ContentNegotiator', 'enabled', false);

		// set language
		$member = Member::currentUser();
		if(!empty($member->Locale)) i18n::set_locale($member->Locale);
		if(!empty($member->DateFormat)) i18n::config()->date_format = $member->DateFormat;
		if(!empty($member->TimeFormat)) i18n::config()->time_format = $member->TimeFormat;

		// can't be done in cms/_config.php as locale is not set yet
		CMSMenu::add_link(
			'Help',
			_t('LeftAndMain.HELP', 'Help', 'Menu title'),
			$this->config()->help_link,
			-2,
			array(
				'target' => '_blank'
			)
		);

		// Allow customisation of the access check by a extension
		// Also all the canView() check to execute Controller::redirect()
		if(!$this->canView() && !$this->response->isFinished()) {
			// When access /admin/, we should try a redirect to another part of the admin rather than be locked out
			$menu = $this->MainMenu();
			foreach($menu as $candidate) {
				if(
					$candidate->Link &&
					$candidate->Link != $this->Link()
					&& $candidate->MenuItem->controller
					&& singleton($candidate->MenuItem->controller)->canView()
				) {
					return $this->redirect($candidate->Link);
				}
			}

			if(Member::currentUser()) {
				Session::set("BackURL", null);
			}

			// if no alternate menu items have matched, return a permission error
			$messageSet = array(
				'default' => _t('LeftAndMain.PERMDEFAULT',
					"Please choose an authentication method and enter your credentials to access the CMS."),
				'alreadyLoggedIn' => _t('LeftAndMain.PERMALREADY',
					"I'm sorry, but you can't access that part of the CMS.  If you want to log in as someone else, do"
					. " so below"),
				'logInAgain' => _t('LeftAndMain.PERMAGAIN',
					"You have been logged out of the CMS.  If you would like to log in again, enter a username and"
					. " password below."),
			);

			return Security::permissionFailure($this, $messageSet);
		}

		// Don't continue if there's already been a redirection request.
		if($this->redirectedTo()) return;

		// Audit logging hook
		if(empty($_REQUEST['executeForm']) && !$this->getRequest()->isAjax()) $this->extend('accessedCMS');

		// Set the members html editor config
		if(Member::currentUser()) {
			HtmlEditorConfig::set_active(Member::currentUser()->getHtmlEditorConfigForCMS());
		}

		// Set default values in the config if missing.  These things can't be defined in the config
		// file because insufficient information exists when that is being processed
		$htmlEditorConfig = HtmlEditorConfig::get_active();
		$htmlEditorConfig->setOption('language', i18n::get_tinymce_lang());
		if(!$htmlEditorConfig->getOption('content_css')) {
			$cssFiles = array();
			$cssFiles[] = FRAMEWORK_ADMIN_DIR . '/css/editor.css';

			// Use theme from the site config
			if(class_exists('SiteConfig') && ($config = SiteConfig::current_site_config()) && $config->Theme) {
				$theme = $config->Theme;
			} elseif(Config::inst()->get('SSViewer', 'theme_enabled') && Config::inst()->get('SSViewer', 'theme')) {
				$theme = Config::inst()->get('SSViewer', 'theme');
			} else {
				$theme = false;
			}

			if($theme) $cssFiles[] = THEMES_DIR . "/{$theme}/css/editor.css";
			else if(project()) $cssFiles[] = project() . '/css/editor.css';

			// Remove files that don't exist
			foreach($cssFiles as $k => $cssFile) {
				if(!file_exists(BASE_PATH . '/' . $cssFile)) unset($cssFiles[$k]);
			}

			$htmlEditorConfig->setOption('content_css', implode(',', $cssFiles));
		}

		// Using uncompressed files as they'll be processed by JSMin in the Requirements class.
		// Not as effective as other compressors or pre-compressed+finetuned files,
		// but overall the unified minification into a single file brings more performance benefits
		// than a couple of saved bytes (after gzip) in individual files.
		// We also re-compress already compressed files through JSMin as this causes weird runtime bugs.
		Requirements::combine_files(
			'lib.js',
			array(
				THIRDPARTY_DIR . '/jquery/jquery.js',
				FRAMEWORK_DIR . '/javascript/jquery-ondemand/jquery.ondemand.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/lib.js',
				THIRDPARTY_DIR . '/jquery-ui/jquery-ui.js',
				THIRDPARTY_DIR . '/json-js/json2.js',
				THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js',
				THIRDPARTY_DIR . '/jquery-cookie/jquery.cookie.js',
				THIRDPARTY_DIR . '/jquery-query/jquery.query.js',
				THIRDPARTY_DIR . '/jquery-form/jquery.form.js',
				FRAMEWORK_ADMIN_DIR . '/thirdparty/jquery-notice/jquery.notice.js',
				FRAMEWORK_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js',
				FRAMEWORK_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js',
				FRAMEWORK_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js',
				FRAMEWORK_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.js',
				FRAMEWORK_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.adapter.jquery.js',
				FRAMEWORK_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.html4.js',
				THIRDPARTY_DIR . '/jstree/jquery.jstree.js',
				FRAMEWORK_ADMIN_DIR . '/thirdparty/chosen/chosen/chosen.jquery.js',
				FRAMEWORK_ADMIN_DIR . '/thirdparty/jquery-hoverIntent/jquery.hoverIntent.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/jquery-changetracker/lib/jquery.changetracker.js',
				FRAMEWORK_DIR . '/javascript/i18n.js',
				FRAMEWORK_DIR . '/javascript/TreeDropdownField.js',
				FRAMEWORK_DIR . '/javascript/DateField.js',
				FRAMEWORK_DIR . '/javascript/HtmlEditorField.js',
				FRAMEWORK_DIR . '/javascript/TabSet.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/ssui.core.js',
				FRAMEWORK_DIR . '/javascript/GridField.js',
			)
		);

		if (Director::isDev()) Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/javascript/leaktools.js');

		$leftAndMainIncludes = array_unique(array_merge(
			array(
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Layout.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.ActionTabSet.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Panel.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Tree.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Content.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.EditForm.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Menu.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Preview.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.BatchActions.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.FieldHelp.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.FieldDescriptionToggle.js',
				FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.TreeDropdownField.js',
			),
			Requirements::add_i18n_javascript(FRAMEWORK_DIR . '/javascript/lang', true, true),
			Requirements::add_i18n_javascript(FRAMEWORK_ADMIN_DIR . '/javascript/lang', true, true)
		));

		if($this->config()->session_keepalive_ping) {
			$leftAndMainIncludes[] = FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Ping.js';
		}

		Requirements::combine_files('leftandmain.js', $leftAndMainIncludes);

		// TODO Confuses jQuery.ondemand through document.write()
		if (Director::isDev()) {
			Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/src/jquery.entwine.inspector.js');
		}

		Requirements::css(FRAMEWORK_ADMIN_DIR . '/thirdparty/jquery-notice/jquery.notice.css');
		Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
		Requirements::css(FRAMEWORK_ADMIN_DIR .'/thirdparty/chosen/chosen/chosen.css');
		Requirements::css(THIRDPARTY_DIR . '/jstree/themes/apple/style.css');
		Requirements::css(FRAMEWORK_DIR . '/css/TreeDropdownField.css');
		Requirements::css(FRAMEWORK_ADMIN_DIR . '/css/screen.css');
		Requirements::css(FRAMEWORK_DIR . '/css/GridField.css');

		// Browser-specific requirements
		$ie = isset($_SERVER['HTTP_USER_AGENT']) ? strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') : false;
		if($ie) {
			$version = substr($_SERVER['HTTP_USER_AGENT'], $ie + 5, 3);

			if($version == 7) {
				Requirements::css(FRAMEWORK_ADMIN_DIR . '/css/ie7.css');
			} else if($version == 8) {
				Requirements::css(FRAMEWORK_ADMIN_DIR . '/css/ie8.css');
			}
		}

		// Custom requirements
		$extraJs = $this->stat('extra_requirements_javascript');

		if($extraJs) {
			foreach($extraJs as $file => $config) {
				if(is_numeric($file)) {
					$file = $config;
				}

				Requirements::javascript($file);
			}
		}

		$extraCss = $this->stat('extra_requirements_css');

		if($extraCss) {
			foreach($extraCss as $file => $config) {
				if(is_numeric($file)) {
					$file = $config;
					$config = array();
				}

				Requirements::css($file, isset($config['media']) ? $config['media'] : null);
			}
		}

		$extraThemedCss = $this->stat('extra_requirements_themedCss');

		if($extraThemedCss) {
			foreach ($extraThemedCss as $file => $config) {
				if(is_numeric($file)) {
					$file = $config;
					$config = array();
				}

				Requirements::themedCSS($file, isset($config['media']) ? $config['media'] : null);
			}
		}

		$dummy = null;
		$this->extend('init', $dummy);

		// The user's theme shouldn't affect the CMS, if, for example, they have
		// replaced TableListField.ss or Form.ss.
		Config::inst()->update('SSViewer', 'theme_enabled', false);
	}

	public function handleRequest(SS_HTTPRequest $request, DataModel $model = null) {
		try {
			$response = parent::handleRequest($request, $model);
		} catch(ValidationException $e) {
			// Nicer presentation of model-level validation errors
			$msgs = _t('LeftAndMain.ValidationError', 'Validation error') . ': '
				. $e->getMessage();
			$e = new SS_HTTPResponse_Exception($msgs, 403);
			$e->getResponse()->addHeader('Content-Type', 'text/plain');
			$e->getResponse()->addHeader('X-Status', rawurlencode($msgs));
			throw $e;
		}

		$title = $this->Title();
		if(!$response->getHeader('X-Controller')) $response->addHeader('X-Controller', $this->class);
		if(!$response->getHeader('X-Title')) $response->addHeader('X-Title', urlencode($title));

		// Prevent clickjacking, see https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
		$this->response->addHeader('X-Frame-Options', 'SAMEORIGIN');
		$this->response->addHeader('Vary', 'X-Requested-With');

		return $response;
	}

	/**
	 * Overloaded redirection logic to trigger a fake redirect on ajax requests.
	 * While this violates HTTP principles, its the only way to work around the
	 * fact that browsers handle HTTP redirects opaquely, no intervention via JS is possible.
	 * In isolation, that's not a problem - but combined with history.pushState()
	 * it means we would request the same redirection URL twice if we want to update the URL as well.
	 * See LeftAndMain.js for the required jQuery ajaxComplete handlers.
	 */
	public function redirect($url, $code=302) {
		if($this->getRequest()->isAjax()) {
			$this->response->addHeader('X-ControllerURL', $url);
			if($this->getRequest()->getHeader('X-Pjax') && !$this->response->getHeader('X-Pjax')) {
				$this->response->addHeader('X-Pjax', $this->getRequest()->getHeader('X-Pjax'));
			}
			$oldResponse = $this->response;
			$newResponse = new LeftAndMain_HTTPResponse(
				$oldResponse->getBody(),
				$oldResponse->getStatusCode(),
				$oldResponse->getStatusDescription()
			);
			foreach($oldResponse->getHeaders() as $k => $v) {
				$newResponse->addHeader($k, $v);
			}
			$newResponse->setIsFinished(true);
			$this->response = $newResponse;
			return ''; // Actual response will be re-requested by client
		} else {
			parent::redirect($url, $code);
		}
	}

	public function index($request) {
		return $this->getResponseNegotiator()->respond($request);
	}

	/**
	 * If this is set to true, the "switchView" context in the
	 * template is shown, with links to the staging and publish site.
	 *
	 * @return boolean
	 */
	public function ShowSwitchView() {
		return false;
	}

	//------------------------------------------------------------------------------------------//
	// Main controllers

	/**
	 * You should implement a Link() function in your subclass of LeftAndMain,
	 * to point to the URL of that particular controller.
	 *
	 * @return string
	 */
	public function Link($action = null) {
		// Handle missing url_segments
		if($this->config()->url_segment) {
			$segment = $this->config()->get('url_segment', Config::FIRST_SET);
		} else {
			$segment = $this->class;
		};

		$link = Controller::join_links(
			$this->stat('url_base', true),
			$segment,
			'/', // trailing slash needed if $action is null!
			"$action"
		);
		$this->extend('updateLink', $link);
		return $link;
	}

	/**
	 * Returns the menu title for the given LeftAndMain subclass.
	 * Implemented static so that we can get this value without instantiating an object.
	 * Menu title is *not* internationalised.
	 */
	public static function menu_title_for_class($class) {
		$title = Config::inst()->get($class, 'menu_title', Config::FIRST_SET);
		if(!$title) $title = preg_replace('/Admin$/', '', $class);
		return $title;
	}

	/**
	 * Return styling for the menu icon, if a custom icon is set for this class
	 *
	 * Example: static $menu-icon = '/path/to/image/';
	 * @param string $class
	 * @return string
	 */
	public static function menu_icon_for_class($class) {
		$icon = Config::inst()->get($class, 'menu_icon', Config::FIRST_SET);
		if (!empty($icon)) {
			$class = strtolower($class);
			return ".icon.icon-16.icon-{$class} { background: url('{$icon}'); } ";
		}
		return '';
	}

	public function show($request) {
		// TODO Necessary for TableListField URLs to work properly
		if($request->param('ID')) $this->setCurrentPageID($request->param('ID'));
		return $this->getResponseNegotiator()->respond($request);
	}

	/**
	 * Caution: Volatile API.
	 *
	 * @return PjaxResponseNegotiator
	 */
	public function getResponseNegotiator() {
		if(!$this->responseNegotiator) {
			$controller = $this;
			$this->responseNegotiator = new PjaxResponseNegotiator(
				array(
					'CurrentForm' => function() use(&$controller) {
						return $controller->getEditForm()->forTemplate();
					},
					'Content' => function() use(&$controller) {
						return $controller->renderWith($controller->getTemplatesWithSuffix('_Content'));
					},
					'Breadcrumbs' => function() use (&$controller) {
						return $controller->renderWith('CMSBreadcrumbs');
					},
					'default' => function() use(&$controller) {
						return $controller->renderWith($controller->getViewer('show'));
					}
				),
				$this->response
			);
		}
		return $this->responseNegotiator;
	}

	//------------------------------------------------------------------------------------------//
	// Main UI components

	/**
	 * Returns the main menu of the CMS.  This is also used by init()
	 * to work out which sections the user has access to.
	 *
	 * @param Boolean
	 * @return SS_List
	 */
	public function MainMenu($cached = true) {
		if(!isset($this->_cache_MainMenu) || !$cached) {
			// Don't accidentally return a menu if you're not logged in - it's used to determine access.
			if(!Member::currentUser()) return new ArrayList();

			// Encode into DO set
			$menu = new ArrayList();
			$menuItems = CMSMenu::get_viewable_menu_items();

			// extra styling for custom menu-icons
			$menuIconStyling = '';

			if($menuItems) {
				foreach($menuItems as $code => $menuItem) {
					// alternate permission checks (in addition to LeftAndMain->canView())

					if(
						isset($menuItem->controller)
						&& $this->hasMethod('alternateMenuDisplayCheck')
						&& !$this->alternateMenuDisplayCheck($menuItem->controller)
					) {
						continue;
					}

					$linkingmode = "link";

					if($menuItem->controller && get_class($this) == $menuItem->controller) {
						$linkingmode = "current";
					} else if(strpos($this->Link(), $menuItem->url) !== false) {
						if($this->Link() == $menuItem->url) {
							$linkingmode = "current";

						// default menu is the one with a blank {@link url_segment}
						} else if(singleton($menuItem->controller)->stat('url_segment') == '') {
							if($this->Link() == $this->stat('url_base').'/') {
								$linkingmode = "current";
							}

						} else {
							$linkingmode = "current";
						}
					}

					// already set in CMSMenu::populate_menu(), but from a static pre-controller
					// context, so doesn't respect the current user locale in _t() calls - as a workaround,
					// we simply call LeftAndMain::menu_title_for_class() again
					// if we're dealing with a controller
					if($menuItem->controller) {
						$defaultTitle = LeftAndMain::menu_title_for_class($menuItem->controller);
						$title = _t("{$menuItem->controller}.MENUTITLE", $defaultTitle);
					} else {
						$title = $menuItem->title;
					}

					// Provide styling for custom $menu-icon. Done here instead of in
					// CMSMenu::populate_menu(), because the icon is part of
					// the CMS right pane for the specified class as well...
					if($menuItem->controller) {
						$menuIcon = LeftAndMain::menu_icon_for_class($menuItem->controller);
						if (!empty($menuIcon)) $menuIconStyling .= $menuIcon;
					}

					$menu->push(new ArrayData(array(
						"MenuItem" => $menuItem,
						"AttributesHTML" => $menuItem->getAttributesHTML(),
						"Title" => Convert::raw2xml($title),
						"Code" => DBField::create_field('Text', $code),
						"Link" => $menuItem->url,
						"LinkingMode" => $linkingmode
					)));
				}
			}
			if ($menuIconStyling) Requirements::customCSS($menuIconStyling);

			$this->_cache_MainMenu = $menu;
		}

		return $this->_cache_MainMenu;
	}

	public function Menu() {
		return $this->renderWith($this->getTemplatesWithSuffix('_Menu'));
	}

	/**
	 * @todo Wrap in CMSMenu instance accessor
	 * @return ArrayData A single menu entry (see {@link MainMenu})
	 */
	public function MenuCurrentItem() {
		$items = $this->MainMenu();
		return $items->find('LinkingMode', 'current');
	}

	/**
	 * Return a list of appropriate templates for this class, with the given suffix using
	 * {@link SSViewer::get_templates_by_class()}
	 *
	 * @return array
	 */
	public function getTemplatesWithSuffix($suffix) {
		return SSViewer::get_templates_by_class(get_class($this), $suffix, 'LeftAndMain');
	}

	public function Content() {
		return $this->renderWith($this->getTemplatesWithSuffix('_Content'));
	}

	public function getRecord($id) {
		$className = $this->stat('tree_class');
		if($className && $id instanceof $className) {
			return $id;
		} else if($className && $id == 'root') {
			return singleton($className);
		} else if($className && is_numeric($id)) {
			return DataObject::get_by_id($className, $id);
		} else {
			return false;
		}
	}

	/**
	 * @return ArrayList
	 */
	public function Breadcrumbs($unlinked = false) {
		$defaultTitle = LeftAndMain::menu_title_for_class($this->class);
		$title = _t("{$this->class}.MENUTITLE", $defaultTitle);
		$items = new ArrayList(array(
			new ArrayData(array(
				'Title' => $title,
				'Link' => ($unlinked) ? false : $this->Link()
			))
		));
		$record = $this->currentPage();
		if($record && $record->exists()) {
			if($record->hasExtension('Hierarchy')) {
				$ancestors = $record->getAncestors();
				$ancestors = new ArrayList(array_reverse($ancestors->toArray()));
				$ancestors->push($record);
				foreach($ancestors as $ancestor) {
					$items->push(new ArrayData(array(
						'Title' => ($ancestor->MenuTitle) ? $ancestor->MenuTitle : $ancestor->Title,
						'Link' => ($unlinked) ? false : Controller::join_links($this->Link('show'), $ancestor->ID)
					)));
				}
			} else {
				$items->push(new ArrayData(array(
					'Title' => ($record->MenuTitle) ? $record->MenuTitle : $record->Title,
					'Link' => ($unlinked) ? false : Controller::join_links($this->Link('show'), $record->ID)
				)));
			}
		}

		return $items;
	}

	/**
	 * @return String HTML
	 */
	public function SiteTreeAsUL() {
		$html = $this->getSiteTreeFor($this->stat('tree_class'));
		$this->extend('updateSiteTreeAsUL', $html);
		return $html;
	}

	/**
	 * Gets the current search filter for this request, if available
	 *
	 * @throws InvalidArgumentException
	 * @return LeftAndMain_SearchFilter
	 */
	protected function getSearchFilter() {
		// Check for given FilterClass
		$params = $this->getRequest()->getVar('q');
		if(empty($params['FilterClass'])) {
			return null;
		}

		// Validate classname
		$filterClass = $params['FilterClass'];
		$filterInfo = new ReflectionClass($filterClass);
		if(!$filterInfo->implementsInterface('LeftAndMain_SearchFilter')) {
			throw new InvalidArgumentException(sprintf('Invalid filter class passed: %s', $filterClass));
		}

		return Injector::inst()->createWithArgs($filterClass, array($params));
	}

	/**
	 * Get a site tree HTML listing which displays the nodes under the given criteria.
	 *
	 * @param $className The class of the root object
	 * @param $rootID The ID of the root object.  If this is null then a complete tree will be
	 *  shown
	 * @param $childrenMethod The method to call to get the children of the tree. For example,
	 *  Children, AllChildrenIncludingDeleted, or AllHistoricalChildren
	 * @return String Nested unordered list with links to each page
	 */
	public function getSiteTreeFor($className, $rootID = null, $childrenMethod = null, $numChildrenMethod = null,
			$filterFunction = null, $nodeCountThreshold = 30) {

		// Filter criteria
		$filter = $this->getSearchFilter();

		// Default childrenMethod and numChildrenMethod
		if(!$childrenMethod) $childrenMethod = ($filter && $filter->getChildrenMethod())
			? $filter->getChildrenMethod()
			: 'AllChildrenIncludingDeleted';

		if(!$numChildrenMethod) {
			$numChildrenMethod = 'numChildren';
			if($filter && $filter->getNumChildrenMethod()) {
				$numChildrenMethod = $filter->getNumChildrenMethod();
			}
		}
		if(!$filterFunction && $filter) {
			$filterFunction = function($node) use($filter) {
				return $filter->isPageIncluded($node);
			};
		}

		// Get the tree root
		$record = ($rootID) ? $this->getRecord($rootID) : null;
		$obj = $record ? $record : singleton($className);

		// Get the current page
		// NOTE: This *must* be fetched before markPartialTree() is called, as this
		// causes the Hierarchy::$marked cache to be flushed (@see CMSMain::getRecord)
		// which means that deleted pages stored in the marked tree would be removed
		$currentPage = $this->currentPage();

		// Mark the nodes of the tree to return
		if ($filterFunction) $obj->setMarkingFilterFunction($filterFunction);

		$obj->markPartialTree($nodeCountThreshold, $this, $childrenMethod, $numChildrenMethod);

		// Ensure current page is exposed
		if($currentPage) $obj->markToExpose($currentPage);

		// NOTE: SiteTree/CMSMain coupling :-(
		if(class_exists('SiteTree')) {
			SiteTree::prepopulate_permission_cache('CanEditType', $obj->markedNodeIDs(),
				'SiteTree::can_edit_multiple');
		}

		// getChildrenAsUL is a flexible and complex way of traversing the tree
		$controller = $this;
		$recordController = ($this->stat('tree_class') == 'SiteTree') ?  singleton('CMSPageEditController') : $this;
		$titleFn = function(&$child, $numChildrenMethod) use(&$controller, &$recordController, $filter) {
			$link = Controller::join_links($recordController->Link("show"), $child->ID);
			$node = LeftAndMain_TreeNode::create($child, $link, $controller->isCurrentPage($child), $numChildrenMethod, $filter);
			return $node->forTemplate();
		};

		// Limit the amount of nodes shown for performance reasons.
		// Skip the check if we're filtering the tree, since its not clear how many children will
		// match the filter criteria until they're queried (and matched up with previously marked nodes).
		$nodeThresholdLeaf = Config::inst()->get('Hierarchy', 'node_threshold_leaf');
		if($nodeThresholdLeaf && !$filterFunction) {
			$nodeCountCallback = function($parent, $numChildren) use(&$controller, $className, $nodeThresholdLeaf) {
				if($className == 'SiteTree' && $parent->ID && $numChildren > $nodeThresholdLeaf) {
					return sprintf(
						'

'
							. '%s (%s)'
							. '

',
						_t('LeftAndMain.TooManyPages', 'Too many pages'),
						Controller::join_links(
							$controller->LinkWithSearch($controller->Link()), '
							?view=list&ParentID=' . $parent->ID
						),
						_t(
							'LeftAndMain.ShowAsList',
							'show as list',
							'Show large amount of pages in list instead of tree view'
						)
					);
				}
			};
		} else {
			$nodeCountCallback = null;
		}

		// If the amount of pages exceeds the node thresholds set, use the callback
		$html = null;
		if($obj->ParentID && $nodeCountCallback) {
			$html = $nodeCountCallback($obj, $obj->$numChildrenMethod());
		}

		// Otherwise return the actual tree (which might still filter leaf thresholds on children)
		if(!$html) {
			$html = $obj->getChildrenAsUL(
				"",
				$titleFn,
				singleton('CMSPagesController'),
				true,
				$childrenMethod,
				$numChildrenMethod,
				$nodeCountThreshold,
				$nodeCountCallback
			);
		}

		// Wrap the root if needs be.
		if(!$rootID) {
			$rootLink = $this->Link('show') . '/root';

			// This lets us override the tree title with an extension
			if($this->hasMethod('getCMSTreeTitle') && $customTreeTitle = $this->getCMSTreeTitle()) {
				$treeTitle = $customTreeTitle;
			} elseif(class_exists('SiteConfig')) {
				$siteConfig = SiteConfig::current_site_config();
				$treeTitle =  Convert::raw2xml($siteConfig->Title);
			} else {
				$treeTitle = '...';
			}

			$html = "

$treeTitle"
				. $html . "

";
		}

		return $html;
	}

	/**
	 * Get a subtree underneath the request param 'ID'.
	 * If ID = 0, then get the whole tree.
	 */
	public function getsubtree($request) {
		$html = $this->getSiteTreeFor(
			$this->stat('tree_class'),
			$request->getVar('ID'),
			null,
			null,
			null,
			$request->getVar('minNodeCount')
		);

		// Trim off the outer tag
		$html = preg_replace('/^[\s\t\r\n]*
]*>/','', $html);
		$html = preg_replace('/<\/ul[^>]*>[\s\t\r\n]*$/','', $html);

		return $html;
	}

	/**
	 * Allows requesting a view update on specific tree nodes.
	 * Similar to {@link getsubtree()}, but doesn't enforce loading
	 * all children with the node. Useful to refresh views after
	 * state modifications, e.g. saving a form.
	 *
	 * @return String JSON
	 */
	public function updatetreenodes($request) {
		$data = array();
		$ids = explode(',', $request->getVar('ids'));
		foreach($ids as $id) {
			if($id === "") continue; // $id may be a blank string, which is invalid and should be skipped over

			$record = $this->getRecord($id);
			if(!$record) continue; // In case a page is no longer available
			$recordController = ($this->stat('tree_class') == 'SiteTree')
				?  singleton('CMSPageEditController')
				: $this;

			// Find the next & previous nodes, for proper positioning (Sort isn't good enough - it's not a raw offset)
			// TODO: These methods should really be in hierarchy - for a start it assumes Sort exists
			$next = $prev = null;

			$className = $this->stat('tree_class');
			$next = DataObject::get($className)
				->filter('ParentID', $record->ParentID)
				->filter('Sort:GreaterThan', $record->Sort)
				->first();

			if (!$next) {
				$prev = DataObject::get($className)
					->filter('ParentID', $record->ParentID)
					->filter('Sort:LessThan', $record->Sort)
					->reverse()
					->first();
			}

			$link = Controller::join_links($recordController->Link("show"), $record->ID);
			$html = LeftAndMain_TreeNode::create($record, $link, $this->isCurrentPage($record))
				->forTemplate() . '
';

			$data[$id] = array(
				'html' => $html,
				'ParentID' => $record->ParentID,
				'NextID' => $next ? $next->ID : null,
				'PrevID' => $prev ? $prev->ID : null
			);
		}
		$this->response->addHeader('Content-Type', 'text/json');
		return Convert::raw2json($data);
	}

	/**
	 * Save  handler
	 */
	public function save($data, $form) {
		$className = $this->stat('tree_class');

		// Existing or new record?
		$id = $data['ID'];
		if(substr($id,0,3) != 'new') {
			$record = DataObject::get_by_id($className, $id);
			if($record && !$record->canEdit()) return Security::permissionFailure($this);
			if(!$record || !$record->ID) $this->httpError(404, "Bad record ID #" . (int)$id);
		} else {
			if(!singleton($this->stat('tree_class'))->canCreate()) return Security::permissionFailure($this);
			$record = $this->getNewItem($id, false);
		}

		// save form data into record
		$form->saveInto($record, true);
		$record->write();
		$this->extend('onAfterSave', $record);
		$this->setCurrentPageID($record->ID);

		$this->response->addHeader('X-Status', rawurlencode(_t('LeftAndMain.SAVEDUP', 'Saved.')));
		return $this->getResponseNegotiator()->respond($this->getRequest());
	}

	public function delete($data, $form) {
		$className = $this->stat('tree_class');

		$id = $data['ID'];
		$record = DataObject::get_by_id($className, $id);
		if($record && !$record->canDelete()) return Security::permissionFailure();
		if(!$record || !$record->ID) $this->httpError(404, "Bad record ID #" . (int)$id);

		$record->delete();

		$this->response->addHeader('X-Status', rawurlencode(_t('LeftAndMain.DELETED', 'Deleted.')));
		return $this->getResponseNegotiator()->respond(
			$this->getRequest(),
			array('currentform' => array($this, 'EmptyForm'))
		);
	}

	/**
	 * Update the position and parent of a tree node.
	 * Only saves the node if changes were made.
	 *
	 * Required data:
	 * - 'ID': The moved node
	 * - 'ParentID': New parent relation of the moved node (0 for root)
	 * - 'SiblingIDs': Array of all sibling nodes to the moved node (incl. the node itself).
	 *   In case of a 'ParentID' change, relates to the new siblings under the new parent.
	 *
	 * @return SS_HTTPResponse JSON string with a
	 */
	public function savetreenode($request) {
		if (!Permission::check('SITETREE_REORGANISE') && !Permission::check('ADMIN')) {
			$this->response->setStatusCode(
				403,
				_t('LeftAndMain.CANT_REORGANISE',
					"You do not have permission to rearange the site tree. Your change was not saved.")
			);
			return;
		}

		$className = $this->stat('tree_class');
		$statusUpdates = array('modified'=>array());
		$id = $request->requestVar('ID');
		$parentID = $request->requestVar('ParentID');

		if($className == 'SiteTree' && $page = DataObject::get_by_id('Page', $id)){
			$root = $page->getParentType();
			if(($parentID == '0' || $root == 'root') && !SiteConfig::current_site_config()->canCreateTopLevel()){
				$this->response->setStatusCode(
					403,
					_t('LeftAndMain.CANT_REORGANISE',
						"You do not have permission to alter Top level pages. Your change was not saved.")
					);
				return;
			}
		}

		$siblingIDs = $request->requestVar('SiblingIDs');
		$statusUpdates = array('modified'=>array());
		if(!is_numeric($id) || !is_numeric($parentID)) throw new InvalidArgumentException();

		$node = DataObject::get_by_id($className, $id);
		if($node && !$node->canEdit()) return Security::permissionFailure($this);

		if(!$node) {
			$this->response->setStatusCode(
				500,
				_t('LeftAndMain.PLEASESAVE',
					"Please Save Page: This page could not be updated because it hasn't been saved yet."
				)
			);
			return;
		}

		// Update hierarchy (only if ParentID changed)
		if($node->ParentID != $parentID) {
			$node->ParentID = (int)$parentID;
			$node->write();

			$statusUpdates['modified'][$node->ID] = array(
				'TreeTitle'=>$node->TreeTitle
			);

			// Update all dependent pages
			if(class_exists('VirtualPage')) {
				$virtualPages = VirtualPage::get()->filter("CopyContentFromID", $node->ID);
				foreach($virtualPages as $virtualPage) {
					$statusUpdates['modified'][$virtualPage->ID] = array(
						'TreeTitle' => $virtualPage->TreeTitle()
					);
				}
			}

			$this->response->addHeader('X-Status',
				rawurlencode(_t('LeftAndMain.REORGANISATIONSUCCESSFUL', 'Reorganised the site tree successfully.')));
		}

		// Update sorting
		if(is_array($siblingIDs)) {
			$counter = 0;
			foreach($siblingIDs as $id) {
				if($id == $node->ID) {
					$node->Sort = ++$counter;
					$node->write();
					$statusUpdates['modified'][$node->ID] = array(
						'TreeTitle' => $node->TreeTitle
					);
				} else if(is_numeric($id)) {
					// Nodes that weren't "actually moved" shouldn't be registered as
					// having been edited; do a direct SQL update instead
					++$counter;
					DB::prepared_query(
						"UPDATE \"$className\" SET \"Sort\" = ? WHERE \"ID\" = ?",
						array($counter, $id)
					);
				}
			}

			$this->response->addHeader('X-Status',
				rawurlencode(_t('LeftAndMain.REORGANISATIONSUCCESSFUL', 'Reorganised the site tree successfully.')));
		}

		return Convert::raw2json($statusUpdates);
	}

	public function CanOrganiseSitetree() {
		return !Permission::check('SITETREE_REORGANISE') && !Permission::check('ADMIN') ? false : true;
	}

	/**
	 * Retrieves an edit form, either for display, or to process submitted data.
	 * Also used in the template rendered through {@link Right()} in the $EditForm placeholder.
	 *
	 * This is a "pseudo-abstract" methoed, usually connected to a {@link getEditForm()}
	 * method in an entwine subclass. This method can accept a record identifier,
	 * selected either in custom logic, or through {@link currentPageID()}.
	 * The form usually construct itself from {@link DataObject->getCMSFields()}
	 * for the specific managed subclass defined in {@link LeftAndMain::$tree_class}.
	 *
	 * @param HTTPRequest $request Optionally contains an identifier for the
	 *  record to load into the form.
	 * @return Form Should return a form regardless wether a record has been found.
	 *  Form might be readonly if the current user doesn't have the permission to edit
	 *  the record.
	 */
	/**
	 * @return Form
	 */
	public function EditForm($request = null) {
		return $this->getEditForm();
	}

	/**
	 * Calls {@link SiteTree->getCMSFields()}
	 *
	 * @param Int $id
	 * @param FieldList $fields
	 * @return Form
	 */
	public function getEditForm($id = null, $fields = null) {
		if(!$id) $id = $this->currentPageID();

		if(is_object($id)) {
			$record = $id;
		} else {
			$record = $this->getRecord($id);
			if($record && !$record->canView()) return Security::permissionFailure($this);
		}

		if($record) {
			$fields = ($fields) ? $fields : $record->getCMSFields();
			if ($fields == null) {
				user_error(
					"getCMSFields() returned null  - it should return a FieldList object.
					Perhaps you forgot to put a return statement at the end of your method?",
					E_USER_ERROR
				);
			}

			// Add hidden fields which are required for saving the record
			// and loading the UI state
			if(!$fields->dataFieldByName('ClassName')) {
				$fields->push(new HiddenField('ClassName'));
			}

			$tree_class = $this->stat('tree_class');
			if(
				$tree_class::has_extension('Hierarchy')
				&& !$fields->dataFieldByName('ParentID')
			) {
				$fields->push(new HiddenField('ParentID'));
			}

			// Added in-line to the form, but plucked into different view by frontend scripts.
			if(in_array('CMSPreviewable', class_implements($record))) {
				$navField = new LiteralField('SilverStripeNavigator', $this->getSilverStripeNavigator());
				$navField->setAllowHTML(true);
				$fields->push($navField);
			}

			if($record->hasMethod('getAllCMSActions')) {
				$actions = $record->getAllCMSActions();
			} else {
				$actions = $record->getCMSActions();
				// add default actions if none are defined
				if(!$actions || !$actions->Count()) {
					if($record->hasMethod('canEdit') && $record->canEdit()) {
						$actions->push(
							FormAction::create('save',_t('CMSMain.SAVE','Save'))
								->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept')
						);
					}
					if($record->hasMethod('canDelete') && $record->canDelete()) {
						$actions->push(
							FormAction::create('delete',_t('ModelAdmin.DELETE','Delete'))
								->addExtraClass('ss-ui-action-destructive')
						);
					}
				}
			}

			// Use <button> to allow full jQuery UI styling
			$actionsFlattened = $actions->dataFields();
			if($actionsFlattened) foreach($actionsFlattened as $action) $action->setUseButtonTag(true);

			$form = CMSForm::create(
				$this, "EditForm", $fields, $actions
			)->setHTMLID('Form_EditForm');
			$form->setResponseNegotiator($this->getResponseNegotiator());
			$form->addExtraClass('cms-edit-form');
			$form->loadDataFrom($record);
			$form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
			$form->setAttribute('data-pjax-fragment', 'CurrentForm');

			// Announce the capability so the frontend can decide whether to allow preview or not.
			if(in_array('CMSPreviewable', class_implements($record))) {
				$form->addExtraClass('cms-previewable');
			}

			// Set this if you want to split up tabs into a separate header row
			// if($form->Fields()->hasTabset()) {
			// 	$form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');
			// }

			// Add a default or custom validator.
			// @todo Currently the default Validator.js implementation
			//  adds javascript to the document body, meaning it won't
			//  be included properly if the associated fields are loaded
			//  through ajax. This means only serverside validation
			//  will kick in for pages+validation loaded through ajax.
			//  This will be solved by using less obtrusive javascript validation
			//  in the future, see http://open.silverstripe.com/ticket/2915 and
			//  http://open.silverstripe.com/ticket/3386
			if($record->hasMethod('getCMSValidator')) {
				$validator = $record->getCMSValidator();
				// The clientside (mainly LeftAndMain*.js) rely on ajax responses
				// which can be evaluated as javascript, hence we need
				// to override any global changes to the validation handler.
				$form->setValidator($validator);
			} else {
				$form->unsetValidator();
			}

			if($record->hasMethod('canEdit') && !$record->canEdit()) {
				$readonlyFields = $form->Fields()->makeReadonly();
				$form->setFields($readonlyFields);
			}
		} else {
			$form = $this->EmptyForm();
		}

		return $form;
	}

	/**
	 * Returns a placeholder form, used by {@link getEditForm()} if no record is selected.
	 * Our javascript logic always requires a form to be present in the CMS interface.
	 *
	 * @return Form
	 */
	public function EmptyForm() {
		$form = CMSForm::create(
			$this,
			"EditForm",
			new FieldList(
				// new HeaderField(
				// 	'WelcomeHeader',
				// 	$this->getApplicationName()
				// ),
				// new LiteralField(
				// 	'WelcomeText',
				// 	sprintf('
%s %s. %s
',
				// 		_t('LeftAndMain_right_ss.WELCOMETO','Welcome to'),
				// 		$this->getApplicationName(),
				// 		_t('CHOOSEPAGE','Please choose an item from the left.')
				// 	)
				// )
			),
			new FieldList()
		)->setHTMLID('Form_EditForm');
		$form->setResponseNegotiator($this->getResponseNegotiator());
		$form->unsetValidator();
		$form->addExtraClass('cms-edit-form');
		$form->addExtraClass('root-form');
		$form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
		$form->setAttribute('data-pjax-fragment', 'CurrentForm');

		return $form;
	}

	/**
	 * Return the CMS's HTML-editor toolbar
	 */
	public function EditorToolbar() {
		return HtmlEditorField_Toolbar::create($this, "EditorToolbar");
	}

	/**
	 * Renders a panel containing tools which apply to all displayed
	 * "content" (mostly through {@link EditForm()}), for example a tree navigation or a filter panel.
	 * Auto-detects applicable templates by naming convention: "<controller classname>_Tools.ss",
	 * and takes the most specific template (see {@link getTemplatesWithSuffix()}).
	 * To explicitly disable the panel in the subclass, simply create a more specific, empty template.
	 *
	 * @return String HTML
	 */
	public function Tools() {
		$templates = $this->getTemplatesWithSuffix('_Tools');
		if($templates) {
			$viewer = new SSViewer($templates);
			return $viewer->process($this);
		} else {
			return false;
		}
	}

	/**
	 * Renders a panel containing tools which apply to the currently displayed edit form.
	 * The main difference to {@link Tools()} is that the panel is displayed within
	 * the element structure of the form panel (rendered through {@link EditForm}).
	 * This means the panel will be loaded alongside new forms, and refreshed upon save,
	 * which can mean a performance hit, depending on how complex your panel logic gets.
	 * Any form fields contained in the returned markup will also be submitted with the main form,
	 * which might be desired depending on the implementation details.
	 *
	 * @return String HTML
	 */
	public function EditFormTools() {
		$templates = $this->getTemplatesWithSuffix('_EditFormTools');
		if($templates) {
			$viewer = new SSViewer($templates);
			return $viewer->process($this);
		} else {
			return false;
		}
	}

	/**
	 * Batch Actions Handler
	 */
	public function batchactions() {
		return new CMSBatchActionHandler($this, 'batchactions', $this->stat('tree_class'));
	}

	/**
	 * @return Form
	 */
	public function BatchActionsForm() {
		$actions = $this->batchactions()->batchActionList();
		$actionsMap = array('-1' => _t('LeftAndMain.DropdownBatchActionsDefault', 'Actions'));
		foreach($actions as $action) $actionsMap[$action->Link] = $action->Title;

		$form = new Form(
			$this,
			'BatchActionsForm',
			new FieldList(
				new HiddenField('csvIDs'),
				DropdownField::create(
					'Action',
					false,
					$actionsMap
				)->setAttribute('autocomplete', 'off')
			),
			new FieldList(
				// TODO i18n
				new FormAction('submit', _t('Form.SubmitBtnLabel', "Go"))
			)
		);
		$form->addExtraClass('cms-batch-actions nostyle');
		$form->unsetValidator();

		$this->extend('updateBatchActionsForm', $form);
		return $form;
	}

	public function printable() {
		$form = $this->getEditForm($this->currentPageID());
		if(!$form) return false;

		$form->transform(new PrintableTransformation());
		$form->setActions(null);

		Requirements::clear();
		Requirements::css(FRAMEWORK_ADMIN_DIR . '/css/LeftAndMain_printable.css');
		return array(
			"PrintForm" => $form
		);
	}

	/**
	 * Used for preview controls, mainly links which switch between different states of the page.
	 *
	 * @return ArrayData
	 */
	public function getSilverStripeNavigator() {
		$page = $this->currentPage();
		if($page) {
			$navigator = new SilverStripeNavigator($page);
			return $navigator->renderWith($this->getTemplatesWithSuffix('_SilverStripeNavigator'));
		} else {
			return false;
		}
	}

	/**
	 * Identifier for the currently shown record,
	 * in most cases a database ID. Inspects the following
	 * sources (in this order):
	 * - GET/POST parameter named 'ID'
	 * - URL parameter named 'ID'
	 * - Session value namespaced by classname, e.g. "CMSMain.currentPage"
	 *
	 * @return int
	 */
	public function currentPageID() {
		if($this->getRequest()->requestVar('ID') && is_numeric($this->getRequest()->requestVar('ID')))	{
			return $this->getRequest()->requestVar('ID');
		} elseif (isset($this->urlParams['ID']) && is_numeric($this->urlParams['ID'])) {
			return $this->urlParams['ID'];
		} elseif(Session::get($this->sessionNamespace() . ".currentPage")) {
			return Session::get($this->sessionNamespace() . ".currentPage");
		} else {
			return null;
		}
	}

	/**
	 * Forces the current page to be set in session,
	 * which can be retrieved later through {@link currentPageID()}.
	 * Keep in mind that setting an ID through GET/POST or
	 * as a URL parameter will overrule this value.
	 *
	 * @param int $id
	 */
	public function setCurrentPageID($id) {
		Session::set($this->sessionNamespace() . ".currentPage", $id);
	}

	/**
	 * Uses {@link getRecord()} and {@link currentPageID()}
	 * to get the currently selected record.
	 *
	 * @return DataObject
	 */
	public function currentPage() {
		return $this->getRecord($this->currentPageID());
	}

	/**
	 * Compares a given record to the currently selected one (if any).
	 * Used for marking the current tree node.
	 *
	 * @return boolean
	 */
	public function isCurrentPage(DataObject $record) {
		return ($record->ID == $this->currentPageID());
	}

	/**
	 * @return String
	 */
	protected function sessionNamespace() {
		$override = $this->stat('session_namespace');
		return $override ? $override : $this->class;
	}

	/**
	 * URL to a previewable record which is shown through this controller.
	 * The controller might not have any previewable content, in which case
	 * this method returns FALSE.
	 *
	 * @return String|boolean
	 */
	public function LinkPreview() {
		return false;
	}

	/**
	 * Return the version number of this application.
	 * Uses the number in <mymodule>/silverstripe_version
	 * (automatically replaced by build scripts).
	 * If silverstripe_version is empty,
	 * then attempts to get it from composer.lock
	 *
	 * @return string
	 */
	public function CMSVersion() {
		$versions = array();
		$modules = array(
			'silverstripe/framework' => array(
				'title' => 'Framework',
				'versionFile' => FRAMEWORK_PATH . '/silverstripe_version',
			)
		);
		if(defined('CMS_PATH')) {
			$modules['silverstripe/cms'] = array(
				'title' => 'CMS',
				'versionFile' => CMS_PATH . '/silverstripe_version',
			);
		}

		// Tries to obtain version number from composer.lock if it exists
		$composerLockPath = BASE_PATH . '/composer.lock';
		if (file_exists($composerLockPath)) {
			$cache = SS_Cache::factory('LeftAndMain_CMSVersion');
			$cacheKey = filemtime($composerLockPath);
			$versions = $cache->load($cacheKey);
			if($versions) {
				$versions = json_decode($versions, true);
			} else {
				$versions = array();
			}
			if(!$versions && $jsonData = file_get_contents($composerLockPath)) {
				$lockData = json_decode($jsonData);
				if($lockData && isset($lockData->packages)) {
					foreach ($lockData->packages as $package) {
						if(
							array_key_exists($package->name, $modules)
							&& isset($package->version)
						) {
							$versions[$package->name] = $package->version;
						}
					}
					$cache->save(json_encode($versions), $cacheKey);
				}
			}
		}

		// Fall back to static version file
		foreach($modules as $moduleName => $moduleSpec) {
			if(!isset($versions[$moduleName])) {
				if($staticVersion = file_get_contents($moduleSpec['versionFile'])) {
					$versions[$moduleName] = $staticVersion;
				} else {
					$versions[$moduleName] = _t('LeftAndMain.VersionUnknown', 'Unknown');
				}
			}
		}

		$out = array();
		foreach($modules as $moduleName => $moduleSpec) {
			$out[] = $modules[$moduleName]['title'] . ': ' . $versions[$moduleName];
		}
		return implode(', ', $out);
	}

	/**
	 * @return array
	 */
	public function SwitchView() {
		if($page = $this->currentPage()) {
			$nav = SilverStripeNavigator::get_for_record($page);
			return $nav['items'];
		}
	}

	/**
	 * @return SiteConfig
	 */
	public function SiteConfig() {
		return (class_exists('SiteConfig')) ? SiteConfig::current_site_config() : null;
	}

	/**
	 * The href for the anchor on the Silverstripe logo.
	 * Set by calling LeftAndMain::set_application_link()
	 *
	 * @config
	 * @var String
	 */
	private static $application_link = 'http://www.silverstripe.org/';

	/**
	 * Sets the href for the anchor on the Silverstripe logo in the menu
	 *
	 * @deprecated since version 4.0
	 *
	 * @param String $link
	 */
	public static function set_application_link($link) {
		Deprecation::notice('4.0', 'Use the "LeftAndMain.application_link" config setting instead');
		Config::inst()->update('LeftAndMain', 'application_link', $link);
	}

	/**
	 * @return String
	 */
	public function ApplicationLink() {
		return $this->stat('application_link');
	}

	/**
	 * The application name. Customisable by calling
	 * LeftAndMain::setApplicationName() - the first parameter.
	 *
	 * @config
	 * @var String
	 */
	private static $application_name = 'SilverStripe';

	/**
	 * @param String $name
	 * @deprecated since version 4.0
	 */
	public static function setApplicationName($name) {
		Deprecation::notice('4.0', 'Use the "LeftAndMain.application_name" config setting instead');
		Config::inst()->update('LeftAndMain', 'application_name', $name);
	}

	/**
	 * Get the application name.
	 *
	 * @return string
	 */
	public function getApplicationName() {
		return $this->stat('application_name');
	}

	/**
	 * @return string
	 */
	public function Title() {
		$app = $this->getApplicationName();

		return ($section = $this->SectionTitle()) ? sprintf('%s - %s', $app, $section) : $app;
	}

	/**
	 * Return the title of the current section. Either this is pulled from
	 * the current panel's menu_title or from the first active menu
	 *
	 * @return string
	 */
	public function SectionTitle() {
		$class = get_class($this);
		$defaultTitle = LeftAndMain::menu_title_for_class($class);
		if($title = _t("{$class}.MENUTITLE", $defaultTitle)) return $title;

		foreach($this->MainMenu() as $menuItem) {
			if($menuItem->LinkingMode != 'link') return $menuItem->Title;
		}
	}

	/**
	 * Return the base directory of the tiny_mce codebase
	 */
	public function MceRoot() {
		return MCE_ROOT;
	}

	/**
	 * Same as {@link ViewableData->CSSClasses()}, but with a changed name
	 * to avoid problems when using {@link ViewableData->customise()}
	 * (which always returns "ArrayData" from the $original object).
	 *
	 * @return String
	 */
	public function BaseCSSClasses() {
		return $this->CSSClasses('Controller');
	}

	/**
	 * @return String
	 */
	public function Locale() {
		return DBField::create_field('DBLocale', i18n::get_locale());
	}

	public function providePermissions() {
		$perms = array(
			"CMS_ACCESS_LeftAndMain" => array(
				'name' => _t('CMSMain.ACCESSALLINTERFACES', 'Access to all CMS sections'),
				'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access'),
				'help' => _t('CMSMain.ACCESSALLINTERFACESHELP', 'Overrules more specific access settings.'),
				'sort' => -100
			)
		);

		// Add any custom ModelAdmin subclasses. Can't put this on ModelAdmin itself
		// since its marked abstract, and needs to be singleton instanciated.
		foreach(ClassInfo::subclassesFor('ModelAdmin') as $i => $class) {
			if($class == 'ModelAdmin') continue;
			if(ClassInfo::classImplements($class, 'TestOnly')) continue;

			$title = _t("{$class}.MENUTITLE", LeftAndMain::menu_title_for_class($class));
			$perms["CMS_ACCESS_" . $class] = array(
				'name' => _t(
					'CMSMain.ACCESS',
					"Access to '{title}' section",
					"Item in permission selection identifying the admin section. Example: Access to 'Files & Images'",
					array('title' => $title)
				),
				'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access')
			);
		}

		return $perms;
	}

	/**
	 * Register the given javascript file as required in the CMS.
	 * Filenames should be relative to the base, eg, FRAMEWORK_DIR . '/javascript/loader.js'
	 *
	 * @deprecated since version 4.0
	 */
	public static function require_javascript($file) {
		Deprecation::notice('4.0', 'Use "LeftAndMain.extra_requirements_javascript" config setting instead');
		Config::inst()->update('LeftAndMain', 'extra_requirements_javascript', array($file => array()));
	}

	/**
	 * Register the given stylesheet file as required.
	 * @deprecated since version 4.0
	 *
	 * @param $file String Filenames should be relative to the base, eg, THIRDPARTY_DIR . '/tree/tree.css'
	 * @param $media String Comma-separated list of media-types (e.g. "screen,projector")
	 * @see http://www.w3.org/TR/REC-CSS2/media.html
	 */
	public static function require_css($file, $media = null) {
		Deprecation::notice('4.0', 'Use "LeftAndMain.extra_requirements_css" config setting instead');
		Config::inst()->update('LeftAndMain', 'extra_requirements_css', array($file => array('media' => $media)));
	}

	/**
	 * Register the given "themeable stylesheet" as required.
	 * Themeable stylesheets have globally unique names, just like templates and PHP files.
	 * Because of this, they can be replaced by similarly named CSS files in the theme directory.
	 *
	 * @deprecated since version 4.0
	 *
	 * @param $name String The identifier of the file.  For example, css/MyFile.css would have the identifier "MyFile"
	 * @param $media String Comma-separated list of media-types (e.g. "screen,projector")
	 */
	public static function require_themed_css($name, $media = null) {
		Deprecation::notice('4.0', 'Use "LeftAndMain.extra_requirements_themedCss" config setting instead');
		Config::inst()->update('LeftAndMain', 'extra_requirements_themedCss', array($name => array('media' => $media)));
	}

}

/**
 * @package cms
 * @subpackage core
 */
class LeftAndMainMarkingFilter {

	/**
	 * @var array Request params (unsanitized)
	 */
	protected $params = array();

	/**
	 * @param array $params Request params (unsanitized)
	 */
	public function __construct($params = null) {
		$this->ids = array();
		$this->expanded = array();
		$parents = array();

		$q = $this->getQuery($params);
		$res = $q->execute();
		if (!$res) return;

		// And keep a record of parents we don't need to get parents
		// of themselves, as well as IDs to mark
		foreach($res as $row) {
			if ($row['ParentID']) $parents[$row['ParentID']] = true;
			$this->ids[$row['ID']] = true;
		}

		// We need to recurse up the tree,
		// finding ParentIDs for each ID until we run out of parents
		while (!empty($parents)) {
			$parentsClause = DB::placeholders($parents);
			$res = DB::prepared_query(
				"SELECT \"ParentID\", \"ID\" FROM \"SiteTree\" WHERE \"ID\" in ($parentsClause)",
				array_keys($parents)
			);
			$parents = array();

			foreach($res as $row) {
				if ($row['ParentID']) $parents[$row['ParentID']] = true;
				$this->ids[$row['ID']] = true;
				$this->expanded[$row['ID']] = true;
			}
		}
	}

	protected function getQuery($params) {
		$where = array();

		if(isset($params['ID'])) unset($params['ID']);
		if($treeClass = static::config()->tree_class) foreach($params as $name => $val) {
			// Partial string match against a variety of fields
			if(!empty($val) && singleton($treeClass)->hasDatabaseField($name)) {
				$predicate = sprintf('"%s" LIKE ?', $name);
				$where[$predicate] = "%$val%";
			}
		}

		return new SQLQuery(
			array("ParentID", "ID"),
			'SiteTree',
			$where
		);
	}

	public function mark($node) {
		$id = $node->ID;
		if(array_key_exists((int) $id, $this->expanded)) $node->markOpened();
		return array_key_exists((int) $id, $this->ids) ? $this->ids[$id] : false;
	}
}

/**
 * Allow overriding finished state for faux redirects.
 *
 * @package framework
 * @subpackage admin
 */
class LeftAndMain_HTTPResponse extends SS_HTTPResponse {

	protected $isFinished = false;

	public function isFinished() {
		return (parent::isFinished() || $this->isFinished);
	}

	public function setIsFinished($bool) {
		$this->isFinished = $bool;
	}

}

/**
 * Wrapper around objects being displayed in a tree.
 * Caution: Volatile API.
 *
 * @todo Implement recursive tree node rendering.
 *
 * @package framework
 * @subpackage admin
 */
class LeftAndMain_TreeNode extends ViewableData {

	/**
	 * Object represented by this node
	 *
	 * @var Object
	 */
	protected $obj;

	/**
	 * Edit link to the current record in the CMS
	 *
	 * @var string
	 */
	protected $link;

	/**
	 * True if this is the currently selected node in the tree
	 *
	 * @var bool
	 */
	protected $isCurrent;

	/**
	 * Name of method to count the number of children
	 *
	 * @var string
	 */
	protected $numChildrenMethod;

	/**
	 *
	 * @var LeftAndMain_SearchFilter
	 */
	protected $filter;

	/**
	 * @param Object $obj
	 * @param string $link
	 * @param bool $isCurrent
	 * @param string $numChildrenMethod
	 * @param LeftAndMain_SearchFilter $filter
	 */
	public function __construct($obj, $link = null, $isCurrent = false,
		$numChildrenMethod = 'numChildren', $filter = null
	) {
		parent::__construct();
		$this->obj = $obj;
		$this->link = $link;
		$this->isCurrent = $isCurrent;
		$this->numChildrenMethod = $numChildrenMethod;
		$this->filter = $filter;
	}

	/**
	 * Returns template, for further processing by {@link Hierarchy->getChildrenAsUL()}.
	 * Does not include closing tag to allow this method to inject its own children.
	 *
	 * @todo Remove hardcoded assumptions around returning an
, by implementing recursive tree node rendering
	 *
	 * @return String
	 */
	public function forTemplate() {
		$obj = $this->obj;
		return "
ID\" data-id=\"$obj->ID\" data-pagetype=\"$obj->ClassName\" class=\""
			. $this->getClasses() . "\">" . " "
			. "getLink() . "\" title=\"" . _t('LeftAndMain.PAGETYPE','Page type: ')
			. "$obj->class\" > " . ($obj->TreeTitle)
			. "";
	}

	/**
	 * Determine the CSS classes to apply to this node
	 *
	 * @return string
	 */
	public function getClasses() {
		// Get classes from object
		$classes = $this->obj->CMSTreeClasses($this->numChildrenMethod);
		if($this->isCurrent) {
			$classes .= ' current';
		}
		// Get status flag classes
		$flags = $this->obj->hasMethod('getStatusFlags')
			? $this->obj->getStatusFlags()
			: false;
		if ($flags) {
			$statuses = array_keys($flags);
			foreach ($statuses as $s) {
				$classes .= ' status-' . $s;
			}
		}
		// Get additional filter classes
		if($this->filter && ($filterClasses = $this->filter->getPageClasses($this->obj))) {
			if(is_array($filterClasses)) {
				$filterClasses = implode(' ' . $filterClasses);
			}
			$classes .= ' ' . $filterClasses;
		}
		return $classes;
	}

	public function getObj() {
		return $this->obj;
	}

	public function setObj($obj) {
		$this->obj = $obj;
		return $this;
	}

	public function getLink() {
		return $this->link;
	}

	public function setLink($link) {
		$this->link = $link;
		return $this;
	}

	public function getIsCurrent() {
		return $this->isCurrent;
	}

	public function setIsCurrent($bool) {
		$this->isCurrent = $bool;
		return $this;
	}

}

/**
 * Abstract interface for a class which may be used to filter the results displayed
 * in a nested tree
 */
interface LeftAndMain_SearchFilter {

	/**
	 * Method on {@link Hierarchy} objects which is used to traverse into children relationships.
	 *
	 * @return string
	 */
	public function getChildrenMethod();

	/**
	 * Method on {@link Hierarchy} objects which is used find the number of children for a parent page
	 *
	 * @return string
	 */
	public function getNumChildrenMethod();

	/**
	 * Returns TRUE if the given page should be included in the tree.
	 * Caution: Does NOT check view permissions on the page.
	 *
	 * @param DataObject $page
	 * @return bool
	 */
	public function isPageIncluded($page);

	/**
	 * Given a page, determine any additional CSS classes to apply to the tree node
	 *
	 * @param DataObject $page
	 * @return array|string
	 */
	public function getPageClasses($page);
}


Be a part of something big on November 20th! Support The Cat Network on GiveMiami Day. Donations will be maximized by a percentage match!
Access to low cost spay neuter services to the public, for feral and stray cats by bringing our Meow Mobile directly to targeted areas and by our network of participating veterinarians in our spay/neuter program . The Cat Network has facilitated almost 90,000 spay/neuter surgeries in 19 years.
In order to keep these program running, we are asking for your support on Give Miami Day.
This year we would like to upgrade our Meow Mobile by purchasing a new awning and getting the vehicle wrapped.
We would also like to offer several free Spay/Neuter days.


We hope you can find everything you need. Thread of Life LLC is focused on providing high-quality service and customer satisfaction - we will do everything we can to meet your expectations.
We are proud to offer direct to garment printing. Leave screen printing behind and create any design with unlimited colors with quantities from 1 to 100 or more.


Each year, NACUFS gives out several national recognition awards to honor individuals and organizations for their outstanding service to the association and its membership. Visit each award's page to view the criteria, eligibility, and past winners for each award, as well as nomination forms.
The Theodore W. Minah Distinguished Service Award is NACUFS' most prestigious honor. Originally established in 1967 as the Distinguished Service Award, it was renamed in 1973 to honor the first recipient, Theodore W. Minah. The award is presented in recognition of exemplary and enduring contributions to the foodservice industry and the association. 2019 individual award nominations were due January 30, 2019.
The David. R. Prentkowski Distinguished Lifetime Member Award was created to honor retired members who have supported the betterment of college and university foodservice and NACUFS. 2019 individual award nominations are were January 30, 2019.
The Daryl Van Hook Industry Award is presented annually to an industry member (individual or organization) based on educational support, product innovation, and service to the association. 2019 individual award nominations are were January 30, 2019.
The Richard Lichtenfelt Award was named after the association's first president, who served from 1958 to 1960. The award recognizes outstanding service to NACUFS on a national level. Recipients are selected by the association president.


text:
15/08/2016 3:31 PM IST | Updated 15/08/2016 3:44 PM IST
Chief Justice Unhappy With PM Modi Skipping Judiciary Issues On Independence Day
It's taking longer to decide cases than it did during the colonial rule
Hindustan Times via Getty Images
Chief Justice of India T S Thakur today expressed dissatisfaction with Prime Minister Narendra Modi not mentioning the problems faced by the judiciary in his speech on the occasion of 70th Independence Day, and said he was expecting some words about the judges' appointments.
"I think I have reached the peak of my career, so I don't hesitate in saying what I feel. So, I should speak the truth which touches your hearts... We heard speeches by the popular Prime Minister, the Law Minister and was expecting something about justice and judges' appointments.
"Cases used to get decided within 10 years under British rule but even that is not happening now. The number of cases and people's expectation have risen so substantially that it is becoming difficult to achieve the objective now. That is why I have time and again requested the Prime Minister to pay attention towards this aspect," the CJI, who had recently made an emotional appeal to the PM in this regard at a function, said.
Union Law Minister Ravi Shankar Prasad, however, said that the appointment of judges would go ahead irrespective of whether new Memorandum of Procedure (MoP) was in place or not.
Prasad said the absence of MoP would not come in the way of the appointment of judges to higher judiciary.
The Centre and the judiciary have been at loggerheads in recent times on finalisation of the Memorandum of Procedure which deals with the appointment of judges in High Courts and the Supreme Court.
The collegium had questioned the Centre's right to reject its recommendation on grounds of national interest and had asked it to change certain other clauses.
The clause on the right to reject a recommendation on national interest is contrary to the current practice where the government is bound to accept a recommendation by the collegium, comprising the CJI and four senior-most judges of the Supreme Court, if it reiterates the same.
Recently, an apex-court bench headed by the CJI had given a stern message to the Centre over non-execution of the collegium's decision to transfer and appoint Chief Justices and judges in High Courts and said that it would not tolerate "logjam in judges' appointment" and would intervene to "fasten accountability" as justice delivery system was "collapsing".
In a function organised by the Supreme Court Bar Association on 70th Independence Day, the CJI said unemployment is a major challenge today and "freedom in real sense is freedom from unemployment and exploitation.
"When we pay homage to our martyrs who lost lives for the sake of the country we should introspect and examine how much we have lived up to their ideals," he said.
MORE: Chief Justice of India judiciary news TS Thakur

redpajama_set_name: RedPajamaCommonCrawl


text:
Slain man's brother frustrated by 23-year wait for justice
Marion Wilson Jr. (Courtesy: Georgia Department of Corrections)
By KATE BRUMBACK, Associated Press
POWDER SPRINGS, Ga. (AP) - Chris Parks is ready to stop checking the number of days since his brother was murdered.
For more than two decades he's periodically tracked how many days go by before the two men convicted of killing him are executed. On Thursday, when the second is scheduled to die, the days will number 8,484.
Marion Wilson Jr. and Robert Earl Butts Jr. were convicted of murder and sentenced to death in the March 1996 slaying of 24-year-old Donovan Corey Parks in Milledgeville, about 90 miles southeast of Atlanta.
The state executed Butts, who was 40, in May 2018. Wilson, 42, is set for execution Thursday.
"What they did to him was not humane. It wasn't fair," Parks said, a tear sliding down his cheek.
That day is etched in Parks' memory. He had dreamed the night before that someone killed his brother, and he was relieved in the morning to see Donovan on the couch.
Before the day ended, his nightmare had become reality.
Parks said his brother went to church the evening of March 28, 1996, and then to Walmart to buy cat food.
Witnesses saw Wilson and Butts, who prosecutors said were gang members, standing behind him in a checkout line. A witness heard Butts ask Parks for a ride.
Butts was in the front passenger seat and Wilson was in the back as they left the parking lot, witnesses said. Wilson told investigators Butts pulled out a sawed-off shotgun, ordered Parks to drive and then ordered Parks out of the car and shot him once in the back of the head, according to court documents. The pair then stole Parks' car.
Parks' father, Freddie, found him lying along the road, but the shotgun did so much damage that he wasn't sure it was his son.
Chris Parks, 42, is frustrated that it's taken more than two decades for Butts and Wilson to be executed.
"Donovan was arrested, tried, convicted, sentenced and executed within 30 minutes for being nice, for being caring," he said.
Meanwhile, he said, Butts and Wilson had years to fight for their lives. Lawyers for both men argued in court filings that the death penalty is an unconstitutionally cruel and unusual punishment.
"What's cruel and unusual is to snatch a man from his vehicle by his necktie so tight that he probably can't speak or breathe," Parks said. "What's cruel and unusual is to lay that man down on the cold asphalt and to take his life as if he was worth nothing more than gum on the bottom of a shoe."
When he died, Donovan Parks was working two jobs - as a prison guard and at a Winn-Dixie grocery store - to make money to study to become a prison counselor.
"He wanted to help those inmates that were in for the long ride, as well as those who were getting ready to transition back to society," Chris Parks said. "He believed that having those conversations and working out those issues that they had would make them better individuals."
Donovan and Chris Parks' mother had died just under a year before Donovan's murder, and the family's house caught fire about six months after. Overwhelmed by tragedy, Chris Parks fled Milledgeville and joined the Army.
He now works in cybersecurity and lives just outside Atlanta with his wife and four children - the oldest, a daughter, named Corey in honor of her late uncle.
Parks thinks about his brother every day and wishes he could call him to complain or seek advice. He's heartbroken that his children were robbed of the opportunity to meet their uncle, who was artistic like Chris' two daughters and sensitive like one of his sons.
Parks witnessed Butts' execution last year.
Georgia executes prisoners using an injection of the sedative pentobarbital. Strapped to a gurney with his arms outstretched to either side, the prisoner appears to fall asleep as witnesses watch from the other side of a large window.
"Honestly, it made me angry," Parks said of Butts' execution. "What I saw was a man who was unremorseful. What I saw was a man being put to sleep as if he were getting a root canal."
Still, he plans to be there again - with his wife, his dad and his stepmother - sitting in the front row of the witness area, to watch Wilson draw his final breaths.
"Execution doesn't bring him back," he said, referring to his brother. "But what execution does is it offers a starting point for myself, my dad, our family, to finally get some sort of closure and to start healing."
What started as an argument at a metro gas station ends with a man in the hospital.
Atlanta Police say just after midnight Wednesday morning, two vehicles pulled into the Exxon on Jonesboro Road outside the Perimeter in southeast Atlanta. Investigators say surveillance video shows after some type of exchange between the people in the vehicles, someone from one of the groups pulled a gun and starting firing. Several shots rang out and one of those rounds struck a man in the stomach.
His friends loaded the victim into a vehicle and drove to nearby Chevron located just across the street from the Crown Road main Post Office. That's where they called 911 for help. Paramedics rushed the man, who is in his mid-twenties, to Grady Memorial Hospital in stable condition.
College student hospitalized after hit and run in Buckhead
The search continued Tuesday for the driver who hit a young woman in Buckhead and fled the scene.
Atlanta police said Chelzie Parmer was crossing the street at Peachtree Road at East Shadowlawn Avenue early Sunday.
"It's almost as if it never slowed down," said Ashia Pace, who was with the 20-year-old victim.


text:
Health Insurance Basics
Insurance Health Insurance
New Drug
By Julia Kagan
Updated Jun 1, 2018
What is New Drug
A new drug is a medication or therapy that has not been used before in clinical practice to treat a disease or condition. A new drug that is marketed in the U.S. must first obtain approval from the Food and Drug Administration.
BREAKING DOWN New Drug
A new drug may be an innovative new compound that is classified as a new molecular entity by the FDA, or it may be related to a previously approved product. Getting FDA approval for a drug is a multi-step process that takes years and millions of dollars.
How a New Drug Gets Approved
The process of getting a new drug to market involves the following steps –
Development of a new drug compound
Animal tests for toxicity, to ensure the compound is safe for humans
Investigational New Drug (IND) application to the NDA
Phase 1 clinical trials or studies, where the emphasis is on the drug's safety and side effects
Phase 2 clinical trials, where the focus is on the proposed drug's effectiveness
Phase 3 clinical trials, which are very large, multi-stage trials that gather more information about the drug's safety and effectiveness
New Drug Application (NDA) to the FDA, which is a comprehensive document containing all the above information
NDA review by the FDA
Drug labeling review and facility inspection by the FDA
Drug approval (or rejection) by the FDA
The FDA's Center for Drug Evaluation and Research, or CDER, is the specific body within the FDA that is involved with reviewing the new drug development process. The CDER has in-depth understanding of the science used to create new products, testing processes and manufacturing procedures, and the diseases and conditions that are sought to be treated by new products. The CDER provides the scientific and regulatory advice needed to bring new products to market.
A new drug candidate can fail at any step of the process, because the clinical trials are meant to establish unequivocally that the drug is safe and effective in treating the targeted indication. However, accelerated versions of the approval process can be employed in certain cases, such as the development of a promising new drug that may treat a rare or life-threatening condition.
The FDA has recently made efforts to increase its rate of drug approvals. The agency 47 new drugs in 2017, compared to 22 in 2016. FDA data shows that the agency has an average rate of 31 new drug approvals per year for the period between 2008 and 2017.
Phase 1 clinical studies or clinical trials are focused on evaluating the safety aspect of the new drug, rather than how effective it may be.
New Drug Application (NDA)
The New Drug Application (NDA) is the formal final step taken by a drug sponsor that applies to the FDA for the approval required to market a new drug.
European Medicines Agency (EMA) is a government entity that promotes access to and approval of medications in European countries.
What You Should Know About Drugs
A drug is a substance used to prevent or cure a disease or ailment or to alleviate its symptoms. In the U.S., drugs may be bought over-the-counter or by doctor's prescription.
Investigational New Drug – IND
An Investigational New Drug (IND) application is the first step in the drug review process, whereby the company submits the application to the FDA.
The Food and Drug Administration is a government agency that regulates certain food, drugs, cosmetics, and medical products.
A Biotech Sector Primer
A Checklist for Medical Technology Investments
Top Biotech Stocks for Q1 2020
Sectors & Industries Analysis
New Drug Development
Services That Health Insurers Often Decline
Pharmaceutical Sector: Does The FDA Help Or Harm?


text:
The 's Luxor Temple And The 250 Statues
Amenhotep III reigned in ancient Egypt from roughly 1391 to 1353 B.C.E. and is most recognized for his construction of The Luxor Temple and hundreds of shrines he had built. (O'Connor, 2001) Throughout the course of this class we have been asked conceptualize different artifacts and determine what this artifact says about the royal figure that contracted it. Amenhotep's Luxor Temple and the 250 statues that he commissioned show us that his reign was focused on impressing the rich and powerful people who surrounded him. This is based on who was intended to see the Luxor temple and what impression the temple would have left on its audience. Historians cite Akhenaten and Tutankhamun as the source of radical change in Egyptian history (Berman, 2001), when in reality Amenhotep III started the legacy of art appreciation that continued on to his successors. Amenhotep's 38 year reign is described as "a period of peace and affluence." (Bryan, 2003) The Pharaoh Amenhotep III was married to Queen Tiyi and a few "lesser wives" he was also the father of Akhenaten, who would grow to become a widely disliked Pharaoh. (Berman, 2001) Amenhotep III encouraged foreign exploration during his reign and was a driving force in international trade. Perhaps this exploration of the world influenced Amenhotep in regard to how he wanted others to perceive him. If anything, the Luxor Temple, and the various artifacts that have been excavated from it display the esteem that this 18th century Egyptian
More about The 's Luxor Temple And The 250 Statues
The Future Of Renewable Energy
Sexual Rape And Sexual Assault
Breast Cancer : Cancer And Cancer
The Industrial Revolution Caused A Major Development During Social History
Challenges Faced With Educating Students With Numeracy Difficulties
Changing Weather Patterns Of The United States


Geographic coordinates are the approximate centre of the area covered by B23 5BY, and are not necessarily those of any specific postal address within it.
B23 5BY is a residential postcode in Birmingham. It was first introduced in June 1981.
The most common council tax bands are C and A. Estimated residential property values, based on historical transactions and adjusted for inflation, range from £119,612 to £228,387 with an average of £174,402. Housing types are typically flats/apartments, semi-detached and terraced (including end of terrace). 41% of house sales since 1995 have been new builds.
In the 2011 census, there were 89 people resident in B23 5BY, of which 48 were male and 41 were female. This includes overnight visitors as well as permanent residents.
B23 5BY is in the Birmingham travel to work area. NHS services are provided by the Birmingham East and North Primary Care Trust.
B23 5BY has a Healthy Living Index of 7/10 (High).
B23 5BY is approximately 114m (374ft) above sea level.
Residents of B23 5BY are represented at different levels of local, regional and national government by elected representatives. Where known, these are shown here.
Ofcom publishes annual statistics for Broadband availability. This is the most recent data for B23 5BY.
The most recent Ofsted rankings for schools near B23 5BY.


New Federal Tax Law – PATH Act – Law Office of Koinonia M. Givens, Esq.
Law Office of Koinonia M. Givens, Esq.
Changes to the way the IRS processes tax returns involving the Earned Income Tax Credit and Additional Child Tax Credit begin Jan. 1, 2017, and may affect some returns filed early in 2017.
How might these changes affect you?
To comply with the law, the IRS will hold the refunds on EITC and ACTC-related returns until Feb. 15.
The IRS will hold the entire refund. Under the new law, the IRS cannot release the part of the refund that is not associated with the EITC and ACTC.
You should file as you normally do.
The IRS will begin accepting and processing electronic tax returns on January 23rd. That will not change.
The IRS still expects to issue most refunds in less than 21 days, though IRS will hold refunds for EITC and ACTC-related tax returns filed early in 2017 until Feb. 15 and then begin issuing them.
This action is driven by the Protecting Americans from Tax Hikes Act of 2015 (PATH Act) that was enacted Dec. 18, 2015, and made several changes to the tax law that are supposed to benefit taxpayers and their families. Section 201 of this new law mandates that no credit or refund for an overpayment for a taxable year shall be made to a taxpayer before Feb. 15 if the taxpayer claimed the Earned Income Tax Credit or Additional Child Tax Credit on the return. This hold by the IRS allows the IRS additional time to help prevent revenue lost due to identity theft and refund fraud related to fabricated wages and withholdings.
*Ask about our Refund Advance, 0% Interest loan, for refund advances of up to $1200.


text:
Reprezentacja Ukrainy U-20 w piłce nożnej jest młodzieżową reprezentacją Ukrainy, sterowaną przez Ukraiński Związek Piłki Nożnej. Jest powoływana przez selekcjonera, w niej występować mogą wyłącznie zawodnicy posiadający obywatelstwo ukraińskie i którzy w momencie przeprowadzania imprezy docelowej (finałów Mistrzostw Świata) nie przekroczyli 20 roku życia.

W 2001, 2005, 2015 i 2019 zespół uczestniczył w młodzieżowych Mistrzostwach Świata U-20 rozgrywanych w Argentynie, Holandii, Nowej Zelandii i Polsce.

W 2019 w turnieju finałowym organizowanym w Polsce zdobyli tytuł mistrza świata.

Historia
Swój pierwszy oficjalny mecz reprezentacja Ukrainy rozegrała 17 czerwca 2001 roku po awansie do Mistrzostwach Świata U-20. Mecz z reprezentacją Chile zakończył się zwycięstwem 4:2.

Udział w turniejach międzynarodowych

Mistrzostwa świata

Dotychczas reprezentacji Ukrainy 4 razy udało się awansować do finałów mistrzostw świata. Najwyższe osiągnięcie to mistrzostwo w 2019 roku.

Selekcjonerzy
 2001:  Anatolij Kroszczenko
 2002–2004: nie była powoływana
 2005:  Ołeksij Mychajłyczenko
 2006–2014: nie była powoływana
 2015:  Ołeksandr Petrakow
 2016–2018: nie była powoływana
 2019:  Ołeksandr Petrakow

Kadra na młodzieżowe Mistrzostwa Świata w 2001
Trener:  Anatolij Kroszczenko

Kadra na młodzieżowe Mistrzostwa Świata w 2005
Trener:  Ołeksij Mychajłyczenko

Kadra na młodzieżowe Mistrzostwa Świata w 2015
Trener:  Ołeksandr Petrakow

Kadra na młodzieżowe Mistrzostwa Świata w 2019
Trener:  Ołeksandr Petrakow

Zobacz też
 reprezentacja Ukrainy w piłce nożnej
 reprezentacja Ukrainy U-21 w piłce nożnej
 reprezentacja Ukrainy U-19 w piłce nożnej
 reprezentacja Ukrainy U-18 w piłce nożnej
 reprezentacja Ukrainy U-17 w piłce nożnej
 reprezentacja Ukrainy U-16 w piłce nożnej

Linki zewnętrzne

Reprezentacja Ukrainy w piłce nożnej
Ukraina

redpajama_set_name: RedPajamaWikipedia


text:
- 0 Articles - 1 Website - 0 Events - 215 User points
Russ Whitney: A True American Story of Determination & Success Expert
Russ Whitney Quick Facts
Main Areas: Real Estate Investing, Stock Investing, Financial Education, Spiritual Life, Creating a Better You, Principles
Best Sellers: Inner Voice, Unlock Your Purpose & Passion, Building Wealth in Real Estate, Millionaire Real Estate Mentor, Millionaire Real Estate Mindset
Career Focus: Author, Speaker, Investor, Business Owner, Self & Spiritual Improvment
Affiliation: Inner Voice, Life Wealth Alliance, Building Life Wealth, Building Wealth, Gulf Stream Construction, Whitney Education Group
Russ Whitney is the epitome of the American Dream: he overcame a difficult youth and went on to build a solid, successful life as a family man, civic leader, philanthropist, best-selling author, mentor and businessperson.
Even as he pursued his legendary business successes, Whitney never neglected the priorities of family, faith and friends. He says his three children (now adults) and granddaughter are his most meaningful achievement and primary motivating force.
Whitney's latest venture, Inner Voice™, is the culmination of a five-year search for the true meaning of life and an understanding of our individual purposes. It has evolved into a community and way of life that is attracting followers around the world.
Russ Whitney, Real Estate Investor
Russ Whitney launched his real estate investing career after reading a book on the subject when he was 20. He was a newly-married high school drop-out working in a slaughterhouse for $5 an hour. That book and Whitney's Inner Voice told him he could do better for himself and his family.
Applying the principles he learned from that book, he began buying income-producing properties. His initial investments were run-down residential properties in low- to moderate-income areas that he would buy, fix up and rent to hard-working people who needed decent, affordable housing. As he gained experience, his portfolio expanded.
Within a few short years, he had achieved financial independence. He was able to quit his job and focus his energy on his investing business full-time. At the age of 27, long before the dot-com phenomenon, he became one of America's youngest self-made millionaires.
Russ Whitney, Entrepreneur & Business Leader
Russ Whitney's many business achievements include founding and building one of the largest and fastest-growing publicly-traded financial education companies of its type in the world. That company created, developed and brought to market such well-known brands as Building Wealth, Teach Me To Trade, Rich Dad Education and more. At its pinnacle, that organization's annual revenue reached $250 million and it provided jobs and career opportunities to more than 2,000 people in seven countries.
Whitney's other entrepreneurial accomplishments include the founding or acquisition of a wide range of businesses, including:
The development of the first bi-weekly mortgage program in the United States in 1984.
A construction firm that built more than 7,000 homes between 2000 and 2006, with revenues approaching $700 million.
A recreational equipment rental business with more than 40 locations worldwide.
Several computer, software and publishing enterprises.
A number of real estate and related entities, including large scale land developments, commercial property development, property management firms and a title company.
The development of a 5,000-acre resort and conference center in Monterey, Costa Rica.
Whitney is a personal, business and strategic advisor to numerous prominent companies, CEOs and investment advisors both nationally and internationally. He has also served on the board of directors for several private and public corporations.
Russ Whitney, Mentor
Personally and through his education products, Russ Whitney has trained millions of individuals around the world in personal success strategies and sound wealth-building techniques, and mentored them as they put their education into practice. He has candidly discussed his own business successes and, more importantly, his mistakes and failures, using them as both learning opportunities and teaching opportunities.
Through the development of the Inner Voice way of life, Whitney discovered that his primary purpose in life is to teach and help others reach their full potential through the Inner Voice experience, education and coaching. He continues to serve as a hands-on coach and mentor to a number of members of the Inner Voice community.
Russ Whitney, Civic Leader & Philanthropist
Russ Whitney has always believed and followed the spiritual tenet that to whom much is given, much is expected (Luke 12:48).
Whitney's own childhood has driven him to take a special interest in programs for children and youth. He spearheaded a successful $2 million fundraiser to build the first Youth Center in his hometown.
Personally and through his companies, Russ Whitney has quietly supported a wide range of charitable organizations, including domestic violence shelters, youth programs, elder programs, Salvation Army services, local food banks, facilities for pregnant teens and single parents, cancer research organizations and more. In addition to being an investor and partner, Whitney also serves as an advisor to several of the largest adult living care facilities in the United States.
As the original developer of Monterey, Whitney built miles of roads, brought in utilities and infrastructure, and created a new and unique city in Costa Rica before the project was sold to another developer. To help assure the local quality of life, he spearheaded efforts to stock the local Red Cross medical center with critical supplies, donating and transporting essential provisions at his own expense.
Russ Whitney has donated time, money and training resources to the Last Chance Ranch, a rural lock-up for at-risk youthful offenders. He has also supplied home study courses and other education materials to incarcerated adults in prisons across the country to assist in their rehabilitation.
Under Whitney's leadership, the Inner Voice brand is committed to supporting programs that serve at-risk youth.
Russ Whitney, Best-selling Author & Speaker
Russ Whitney is a best-selling author and popular speaker who has shared the stage with some of the world's most respected motivational and entrepreneurial thought leaders, including the late Lady Margaret Thatcher, Britain's first female prime minister; former U.S. Presidents George H.W. Bush and Bill Clinton; as well as well-known figures such as Tony Robbins, George Foreman and others. His inspirational message goes beyond motivation – he delivers a life-changing action plan that has positively impacted millions of people.
Whitney began his public speaking career in 1985 with the publication of his first book, Hurdles & Pitfalls. Over the years, he has appeared in venues of all sizes around the world, with audiences ranging from a small class to auditoriums packed with as many as 30,000 enthusiastic fans.
Russ Whitney is the author of more than 30 books, audio and video collections and training programs on entrepreneurship, business, real estate and investing.
Russ Whitney's books include:
Hurdles & Pitfalls of Real Estate Investing (National Institute of Financial Planning)
Building Wealth (Simon & Schuster)
Millionaire Real Estate Mentor (Dearborn)
The Millionaire Real Estate Mindset (Doubleday)
One in a Million 90 Day Challenge
INNER VOICE: Unlock Your Purpose & Passion (Hay House)
Free Articles & Book Excerpts
Should You Get Your Real Estate License? > The Inside Scoop on How it Can Help – and Hurt
Four Steps to Choosing a Realtor that Will Work for YOU
And How It Can Bring You 10 Times More Cash Flow!
Re-write Your Destiny and Take Control of Your Life
Learn to Recognize Your Most Valuable Asset and Make it Work for You
Three Easy Ways to Reach Your Goal Faster
Uncle Sam Wants to Double Your Money
The Secret to Long-Lasting Success
Don't Let the Haters Get You Down
The single, BEST way to get started with NO money!
Be a Kitchen Table CEO
Russ Whitney Audio & Video Programs
Building Life Wealth Quick Start Guide
Art Of Human Engineering
Wealth Master On Demand Training
Foreclosure On Demand Training
Wholesale Buying On Demand Training
Lease Option / Purchase Option On Demand Training
Tax Liens & Deeds On Demand Training
Probate Investing On Demand Training
Millionaire U Training Live With Russ Whitney
Live In Home Mentoring
Live One-On-One Phone Coaching
Russ Whitney Books
Inner Voice - Unlock Your Purpose & Passion
Millionaire Real Estate Mentor
Millionaire Real Estate Mindset
Overcoming The Hurdles & Pitfalls of Real Estate Investing
Other Programs & Highlights
LifeWealth Alliance will share the most revealing truths about success, which have ever been discussed on this planet! We will teach you how to accomplish more tasks and find more ways to become financially independent. Most importantly, we will teach you how to have a better ratio of peace and joy in your life like you never had before while being more productive in every facet of your life! You will learn how to make more money, achieve success, have more happiness in relationships, and bring more balance to your life. This all will happen while you fulfill whatever it is you were put here on earth to do. In LifeWealth Alliance we grow, stretch, and reach our fullest potential through practice of the LWA Success Phases and Principles. Make sure you get registered for each LIVE INNER VOICE webinar.REGISTER HERE.
Favorite Quotes & Thoughts from Russ Whitney
Contacting Russ Whitney
Russ Whitney www.InnerVoice.com Customer Support Support@InnerVoice.com Customer Service 877-701-3326
David Riklan Steve Toth Christine Dreher, ... Peter Games James Goi Jr. Father Time G L Asaf Shani


text:
World Map / Germany Map / States / Saarland Map
Interesting Questions & Answers
Saarland Map
Saarland State is the smallest state in Germany with respect to area as well as population. Its capital is Saarbrucken. The state is located at the border between France and Germany that gives it a unique and rare history.
More Saarland Maps
Saarland Blank Map
Saarland Rail Map
Saarland Road Map
Also Explore: Saarland Karte
Saarland is located in the south western part of Germany. The state comprises an area of just 2,570 square kilometers and a population of 1,012,000, making it the smallest state in the country both in terms of population as well as area. The capital of Saarland is located at Saarbrücken.
Saarland owes its existence to the League of Nations. The territory, which did not exist before the outbreak of WW1 as some parts belonged to Prussia while others to Bavaria, was created by the League of Nations after the end of the Great War as the Territory of the Saar Basin. A referendum was held in 1935 where the inhabitants of the region overwhelmingly voted to rejoin Germany. Following the end of the Second World War, the region was separated from the rest of Germany and placed under french protection. It remained a French-occupied territory from 1947 to 1956. In a referendum that was held, people living in the region were offered independence while staying in economic union with France. However, its rejection by voters indicated that they chose to reunite with West Germany.
Places to visit in Saarland
There are numerous places of attractions that one can visit in Saarland. Some of them are: Get to know all about Dinosaurs by visiting the exciting museum Gondwana - Das Praehistorium; Montclair Castle, a medieval castle abandoned in 1606; Saarland State Theater; Abbey Park, a nice place to spend a day with your family; St. Joseph's Chapel; Wolfspark Merzig, take a look at the wolves from different habitats from around the world. These are some of the interesting tourist attractions of the place.
How to get to Saarland
Some of the airports that are either located in or in close proximity to Saarland and offer flights to other German states as well as countries around the world are Saarbrücken, Luxembourg and Hahn. The state is well-connected by rail and if you are coming from beyond the borders of Germany, then hop on to the high-speed ICE/TGV trains which ply between Paris and Frankfurt and make a stop at Saarbrücken. However, if you are traveling to Saarland from some other German state, then you can take an IC and ICE trains from cities such as Dresden, Mannheim, Munich, among others.
Must Explore Germany States Map
Berlin Map Saarland Map Brandenburg Map
Hamburg Map Rheinland Pfalz Map Hessen Maps
Baden Wurttemberg Map Niedersachsen Map Mecklenburg Vorpommern Map
Nordrhein Westfalen Map Schleswig Holstein Map Bayern Map
Sachsen Map Thuringia Map Sachsen Anhalt Map
Districts in Saarland
Area(km.²)
Merzig-Wadern MW Merzig 103,636 555
Neunkirchen NU Ottweiler 135,531 249
Saarbrücken SB Saarbrücken 327,065 411
Saarlouis SA Saarlouis 197,877 459
Saarpfalz-Kreis SP Homburg 145,394 419
St. Wendel SW St. Wendel 90,120 476
Find Germany States Maps in German Language
Bundesländer Deutschland Karte - Bundesländer und ihrer Hauptstadte
Baden Württemberg Karte Hessen Karte Saarland Karte
Bayern Karte Mecklenburg-vorpommern Karte Sachsen Anhalt Karte
Berlin Karte Niedersachsen Karte Sachsen Karte
Brandenburg Karte Nordrhein-westfalen Karte Schleswig Holstein Karte
Bremen Karte Rheinland-pfalz Karte Thüringen Karte
Hamburg Karte
Last Updated : November 03, 2016