text:
<?php

namespace ElkArte\Controller;

use BBC\ParserWrapper;
use ElkArte\AbstractController;
use ElkArte\Action;
use ElkArte\Cache\Cache;
use ElkArte\Exceptions\Exception;
use ElkArte\MessagesDelete;
use ElkArte\User;
use ElkArte\Util;

/**
 * Provides overview of moderation items to the team
 */
class ModerationCenter extends AbstractController
{
	/**
	 * Holds function array to pass to callMenu to call the right moderation area
	 *
	 * @var array
	 */
	private $_mod_include_data;

	/**
	 * Entry point for the moderation center.
	 *
	 * @see \ElkArte\AbstractController::action_index()
	 */
	public function action_index()
	{
		// Set up moderation menu.
		$this->prepareModcenter();

		callMenu($this->_mod_include_data);
	}

	/**
	 * Prepare menu, make checks, load files, and create moderation menu.
	 *
	 * This can be called from the class, or from outside, to
	 * set up moderation menu.
	 */
	public function prepareModcenter()
	{
		global $txt, $context, $modSettings, $options;

		// Don't run this twice... and don't conflict with the admin bar.
		if (isset($context['admin_area']))
		{
			return;
		}

		$context['can_moderate_boards'] = $this->user->mod_cache['bq'] != '0=1';
		$context['can_moderate_groups'] = $this->user->mod_cache['gq'] != '0=1';
		$context['can_moderate_approvals'] = $modSettings['postmod_active'] && !empty($this->user->mod_cache['ap']);

		// Everyone using this area must be allowed here!
		if (!$context['can_moderate_boards'] && !$context['can_moderate_groups'] && !$context['can_moderate_approvals'])
		{
			isAllowedTo('access_mod_center');
		}

		// We're gonna want a menu of some kind.
		require_once(SUBSDIR . '/Menu.subs.php');

		// Load the language, and the template.
		\ElkArte\Themes\ThemeLoader::loadLanguageFile('ModerationCenter');
		loadCSSFile('admin.css');

		if (!empty($options['admin_preferences']))
		{
			$context['admin_preferences'] = serializeToJson($options['admin_preferences'], function ($array_form) {
				global $context;

				$context['admin_preferences'] = $array_form;
				require_once(SUBSDIR . '/Admin.subs.php');
				updateAdminPreferences();
			});
		}
		else
		{
			$context['admin_preferences'] = array();
		}

		$context['robot_no_index'] = true;

		// Moderation counts for things that this moderator can take care of
		require_once(SUBSDIR . '/Moderation.subs.php');
		$mod_counts = loadModeratorMenuCounts();

		// This is the menu structure - refer to subs/Menu.subs.php for the details.
		$moderation_areas = array(
			'main' => array(
				'title' => $txt['mc_main'],
				'areas' => array(
					'index' => array(
						'label' => $txt['moderation_center'],
						'controller' => '\\ElkArte\\Controller\\ModerationCenter',
						'function' => 'action_moderationHome',
						'icon' => 'transparent.png',
						'class' => 'admin_img_home',
					),
					'settings' => array(
						'label' => $txt['mc_settings'],
						'controller' => '\\ElkArte\\Controller\\ModerationCenter',
						'function' => 'action_moderationSettings',
						'icon' => 'transparent.png',
						'class' => 'admin_img_features',
					),
					'modlogoff' => array(
						'label' => $txt['mc_logoff'],
						'controller' => '\\ElkArte\\Controller\\ModerationCenter',
						'function' => 'action_modEndSession',
						'enabled' => empty($modSettings['securityDisable_moderate']),
						'icon' => 'transparent.png',
						'class' => 'admin_img_exit',
					),
					'notice' => array(
						'controller' => '\\ElkArte\\Controller\\ModerationCenter',
						'function' => 'action_showNotice',
						'select' => 'index',
						'icon' => 'transparent.png',
						'class' => 'admin_img_news',
					),
				),
			),
			'logs' => array(
				'title' => $txt['mc_logs'],
				'areas' => array(
					'modlog' => array(
						'label' => $txt['modlog_view'],
						'enabled' => !empty($modSettings['modlog_enabled']) && $context['can_moderate_boards'],
						'controller' => '\\ElkArte\\AdminController\\Modlog',
						'function' => 'action_log',
						'icon' => 'transparent.png',
						'class' => 'admin_img_logs',
					),
					'warnings' => array(
						'label' => $txt['mc_warnings'],
						'enabled' => featureEnabled('w') && !empty($modSettings['warning_enable']) && $context['can_moderate_boards'],
						'controller' => '\\ElkArte\\Controller\\ModerationCenter',
						'function' => 'action_viewWarnings',
						'icon' => 'transparent.png',
						'class' => 'admin_img_reports',
						'subsections' => array(
							'log' => array($txt['mc_warning_log']),
							'templates' => array($txt['mc_warning_templates'], 'issue_warning'),
						),
					),
				),
			),
			'posts' => array(
				'title' => $txt['mc_posts'] . (!empty($mod_counts['pt_total']) ? ' [' . $mod_counts['pt_total'] . ']' : ''),
				'enabled' => $context['can_moderate_boards'] || $context['can_moderate_approvals'],
				'areas' => array(
					'postmod' => array(
						'label' => $txt['mc_unapproved_posts'] . (!empty($mod_counts['postmod']) ? ' [' . $mod_counts['postmod'] . ']' : ''),
						'enabled' => $context['can_moderate_approvals'],
						'controller' => '\\ElkArte\\Controller\\PostModeration',
						'function' => 'action_index',
						'icon' => 'transparent.png',
						'class' => 'admin_img_posts',
						'custom_url' => getUrl('action', ['action' => 'moderate', 'area' => 'postmod']),
						'subsections' => array(
							'posts' => array($txt['mc_unapproved_replies']),
							'topics' => array($txt['mc_unapproved_topics']),
						),
					),
					'emailmod' => array(
						'label' => $txt['mc_emailerror'] . (!empty($mod_counts['emailmod']) ? ' [' . $mod_counts['emailmod'] . ']' : ''),
						'enabled' => !empty($modSettings['maillist_enabled']) && allowedTo('approve_emails'),
						'function' => 'UnapprovedEmails',
						'icon' => 'transparent.png',
						'class' => 'admin_img_mail',
						'custom_url' => getUrl('action', ['action' => 'moderate', 'area' => 'maillist', 'sa' => 'emaillist']),
					),
					'attachmod' => array(
						'label' => $txt['mc_unapproved_attachments'] . (!empty($mod_counts['attachments']) ? ' [' . $mod_counts['attachments'] . ']' : ''),
						'enabled' => $context['can_moderate_approvals'],
						'controller' => '\\ElkArte\\Controller\\PostModeration',
						'function' => 'action_index',
						'icon' => 'transparent.png',
						'class' => 'admin_img_attachment',
						'custom_url' => getUrl('action', ['action' => 'moderate', 'area' => 'attachmod', 'sa' => 'attachments']),
					),
					'reports' => array(
						'label' => $txt['mc_reported_posts'] . (!empty($mod_counts['reports']) ? ' [' . $mod_counts['reports'] . ']' : ''),
						'enabled' => $context['can_moderate_boards'],
						'controller' => '\\ElkArte\\Controller\\ModerationCenter',
						'function' => 'action_reportedPosts',
						'icon' => 'transparent.png',
						'class' => 'admin_img_reports',
						'subsections' => array(
							'open' => array($txt['mc_reportedp_active'] . (!empty($mod_counts['reports']) ? ' [' . $mod_counts['reports'] . ']' : '')),
							'closed' => array($txt['mc_reportedp_closed']),
						),
					),
					'pm_reports' => array(
						'label' => $txt['mc_reported_pms'] . (!empty($mod_counts['pm_reports']) ? ' [' . $mod_counts['pm_reports'] . ']' : ''),
						'enabled' => $this->user->is_admin,
						'controller' => '\\ElkArte\\Controller\\ModerationCenter',
						'function' => 'action_reportedPosts',
						'subsections' => array(
							'open' => array($txt['mc_reportedp_active']),
							'closed' => array($txt['mc_reportedp_closed']),
						),
					),
				),
			),
			'groups' => array(
				'title' => $txt['mc_groups'] . (!empty($mod_counts['mg_total']) ? ' [' . $mod_counts['mg_total'] . ']' : ''),
				'enabled' => $context['can_moderate_groups'],
				'areas' => array(
					'userwatch' => array(
						'label' => $txt['mc_watched_users_title'],
						'enabled' => featureEnabled('w') && !empty($modSettings['warning_enable']) && $context['can_moderate_boards'],
						'controller' => '\\ElkArte\\Controller\\ModerationCenter',
						'function' => 'action_viewWatchedUsers',
						'icon' => 'transparent.png',
						'class' => 'admin_img_permissions',
						'subsections' => array(
							'member' => array($txt['mc_watched_users_member']),
							'post' => array($txt['mc_watched_users_post']),
						),
					),
					'groups' => array(
						'label' => $txt['mc_group_requests'] . (!empty($mod_counts['groupreq']) ? ' [' . $mod_counts['groupreq'] . ']' : ''),
						'controller' => '\\ElkArte\\Controller\\Groups',
						'function' => 'action_index',
						'icon' => 'transparent.png',
						'class' => 'admin_img_regcenter',
						'custom_url' => getUrl('action', ['action' => 'moderate', 'area' => 'groups', 'sa' => 'requests']),
					),
					'members' => array(
						'enabled' => allowedTo('moderate_forum'),
						'label' => $txt['mc_member_requests'] . (!empty($mod_counts['memberreq']) ? ' [' . $mod_counts['memberreq'] . ']' : ''),
						'controller' => '\\ElkArte\\AdminController\\ManageMembers',
						'function' => 'action_approve',
						'icon' => 'transparent.png',
						'class' => 'admin_img_members',
						'custom_url' => getUrl('admin', ['action' => 'admin', 'area' => 'viewmembers', 'sa' => 'browse', 'type' => 'approve']),
					),
					'viewgroups' => array(
						'label' => $txt['mc_view_groups'],
						'controller' => '\\ElkArte\\Controller\\Groups',
						'function' => 'action_index',
						'icon' => 'transparent.png',
						'class' => 'admin_img_membergroups',
					),
				),
			),
		);

		// Make sure the administrator has a valid session...
		validateSession('moderate');

		// I don't know where we're going - I don't know where we've been...
		$menuOptions = array(
			'action' => 'moderate',
			'hook' => 'moderation',
			'disable_url_session_check' => true,
		);

		// Setup the menu
		$mod_include_data = createMenu($moderation_areas, $menuOptions);
		unset($moderation_areas);

		// Retain the ID information in case required by a subaction.
		$context['moderation_menu_id'] = $context['max_menu_id'];
		$context['moderation_menu_name'] = 'menu_data_' . $context['moderation_menu_id'];
		$context[$context['moderation_menu_name']]['tab_data'] = array(
			'title' => $txt['moderation_center'],
			'help' => '',
			'description' => sprintf($txt['mc_description'], $context['user']['name'], getUrl('action', ['action' => 'moderate', 'area' => 'settings'])));

		// What a pleasant shortcut - even tho we're not *really* on the admin screen who cares...
		$context['admin_area'] = $mod_include_data['current_area'];

		// Build the link tree.
		$context['linktree'][] = array(
			'url' => getUrl('action', ['action' => 'moderate']),
			'name' => $txt['moderation_center'],
		);

		if (isset($mod_include_data['current_area']) && $mod_include_data['current_area'] != 'index')
		{
			$context['linktree'][] = array(
				'url' => getUrl('action', ['action' => 'moderate', 'area' => $mod_include_data['current_area']]),
				'name' => $mod_include_data['label'],
			);
		}

		if (!empty($mod_include_data['current_subsection']) && isset($mod_include_data['subsections'][$mod_include_data['current_subsection']]['label'])
			&& $mod_include_data['subsections'][$mod_include_data['current_subsection']]['label'] !== $mod_include_data['label'])
		{
			$context['linktree'][] = array(
				'url' => getUrl('action', ['action' => 'moderate', 'area' => $mod_include_data['current_area'], 'sa' => $mod_include_data['current_subsection']]),
				'name' => $mod_include_data['subsections'][$mod_include_data['current_subsection']]['label'],
			);
		}

		// Finally, store this, so that if we're called from the class, it can use it.
		$this->_mod_include_data = $mod_include_data;
	}

	/**
	 * This handler presents the home page of the moderation center.
	 */
	public function action_moderationHome()
	{
		global $txt, $context;

		theme()->getTemplates()->load('ModerationCenter');
		loadJavascriptFile('admin.js', array(), 'admin_scripts');

		$context['page_title'] = $txt['moderation_center'];
		$context['sub_template'] = 'moderation_center';

		// Start off with no blocks
		$valid_blocks = array();

		// Load what blocks the user actually can see...
		$valid_blocks['p'] = 'notes';
		$valid_blocks['n'] = 'latestNews';

		if ($context['can_moderate_boards'])
		{
			$valid_blocks['a'] = 'actionRequired';
			$valid_blocks['r'] = 'reportedPosts';
			$valid_blocks['w'] = 'watchedUsers';
		}

		if ($context['can_moderate_groups'])
		{
			$valid_blocks['g'] = 'groupRequests';
		}

		if (empty(User::$settings['mod_prefs']))
		{
			$user_blocks = 'n' . ($context['can_moderate_boards'] ? 'wra' : '') . ($context['can_moderate_groups'] ? 'g' : '');
		}
		else
		{
			list (, $user_blocks) = explode('|', User::$settings['mod_prefs']);
		}

		$user_blocks = str_split($user_blocks);

		$context['mod_blocks'] = array();
		foreach ($valid_blocks as $k => $block)
		{
			if (in_array($k, $user_blocks))
			{
				$block = 'block_' . $block;

				if (method_exists($this, $block))
				{
					$context['mod_blocks'][] = $this->{$block}();
				}
			}
		}
	}

	/**
	 * This ends a moderator session, requiring authentication to access the MCP again.
	 */
	public function action_modEndSession()
	{
		// This is so easy!
		unset($_SESSION['moderate_time']);

		// Clean any moderator tokens as well.
		cleanTokens(false, '-mod');

		redirectexit('action=moderate');
	}

	/**
	 * Show a warning notice sent to a user.
	 */
	public function action_showNotice()
	{
		global $txt, $context;

		// What notice have they asked to view
		$id_notice = $this->_req->getQuery('nid', 'intval', 0);
		$notice = moderatorNotice($id_notice);

		// legit?
		if (empty($notice) || !$context['can_moderate_boards'])
		{
			throw new Exception('no_access', false);
		}

		list ($context['notice_body'], $context['notice_subject']) = $notice;

		$parser = ParserWrapper::instance();

		$context['notice_body'] = $parser->parseNotice($context['notice_body']);
		$context['page_title'] = $txt['show_notice'];
		$context['sub_template'] = 'show_notice';

		theme()->getLayers()->removeAll();
		theme()->getTemplates()->load('ModerationCenter');
	}

	/**
	 * Browse all the reported posts.
	 *
	 * @todo this needs to be given its own file?
	 */
	public function action_reportedPosts()
	{
		global $txt, $context;

		theme()->getTemplates()->load('ModerationCenter');
		require_once(SUBSDIR . '/Moderation.subs.php');

		// Put the open and closed options into tabs, because we can...
		$context[$context['moderation_menu_name']]['tab_data'] = array(
			'title' => $txt['mc_reported_posts'],
			'help' => '',
			'description' => $txt['mc_reported_posts_desc'],
		);

		// Set up the comforting bits...
		$context['page_title'] = $txt['mc_reported_posts'];
		$context['sub_template'] = 'reported_posts';

		// This comes under the umbrella of moderating posts.
		if ($this->user->mod_cache['bq'] === '0=1')
		{
			isAllowedTo('moderate_forum');
		}

		// Are they wanting to view a particular report?
		if (!empty($this->_req->query->report))
		{
			return $this->action_modReport();
		}

		// This should not be needed...
		$show_pms = false;
		if ($context['admin_area'] === 'pm_reports')
		{
			$show_pms = true;
			isAllowedTo('admin_forum');

			// Put the open and closed options into tabs, because we can...
			$context[$context['moderation_menu_name']]['tab_data'] = array(
				'title' => $txt['mc_reported_pms'],
				'help' => '',
				'description' => $txt['mc_reported_pms_desc'],
			);
			$context['page_title'] = $txt['mc_reported_pms'];
		}

		// Are we viewing open or closed reports?
		$context['view_closed'] = $this->_req->getQuery('sa') === 'closed' ? 1 : 0;

		// Are we doing any work?
		if ((isset($this->_req->query->ignore) || isset($this->_req->query->close)) && isset($this->_req->query->rid))
		{
			checkSession('get');
			$rid = $this->_req->getQuery('rid', 'intval');

			// Update the report...
			if (isset($this->_req->query->ignore))
			{
				updateReportsStatus($rid, 'ignore', (int) $this->_req->query->ignore);
			}
			elseif (isset($this->_req->query->close))
			{
				updateReportsStatus($rid, 'close', (int) $this->_req->query->close);
			}

			// Time to update.
			updateSettings(array('last_mod_report_action' => time()));
			recountOpenReports(true, $show_pms);
		}
		elseif (isset($this->_req->post->close) && isset($this->_req->post->close_selected))
		{
			checkSession('post');

			// All the ones to update...
			$toClose = array_map('intval', $this->_req->post->close);
			if (!empty($toClose))
			{
				updateReportsStatus($toClose, 'close', 1);

				// Time to update.
				updateSettings(array('last_mod_report_action' => time()));
				recountOpenReports(true, $show_pms);
			}
		}

		// How many entries are we viewing?
		$context['total_reports'] = totalReports($context['view_closed'], $show_pms);

		// So, that means we can page index, yes?
		$context['page_index'] = constructPageIndex('{scripturl}?action=moderate;area=' . $context['admin_area'] . ($context['view_closed'] ? ';sa=closed' : ''), $this->_req->query->start, $context['total_reports'], 10);
		$context['start'] = $this->_req->query->start;

		// By George, that means we in a position to get the reports, golly good.
		$context['reports'] = getModReports($context['view_closed'], $context['start'], 10, $show_pms);
		$report_ids = array_keys($context['reports']);
		$report_boards_ids = array();
		$bbc_parser = ParserWrapper::instance();
		foreach ($context['reports'] as $row)
		{
			$context['reports'][$row['id_report']] = array(
				'board' => $row['id_board'],
				'id' => $row['id_report'],
				'topic_href' => getUrl('topic', ['topic' => $row['id_topic'], 'msg' =>  $row['id_msg'], 'start' => $row['id_msg'], 'hash' => '#msg' . $row['id_msg']]),
				'report_href' => getUrl('action', ['action' => 'moderate', 'area' => $context['admin_area'], 'report' => $row['id_report']]),
				'author' => array(
					'id' => $row['id_author'],
					'name' => $row['author_name'],
					'link' => $row['id_author'] ? ' 'profile', 'u' => $row['id_author']]) . '">' . $row['author_name'] . '' : $row['author_name'],
					'href' => getUrl('profile', ['action' => 'profile', 'u' => $row['id_author']]),
				),
				'comments' => array(),
				'time_started' => standardTime($row['time_started']),
				'last_updated' => standardTime($row['time_updated']),
				'subject' => $row['subject'],
				'body' => $bbc_parser->parseReport($row['body']),
				'num_reports' => $row['num_reports'],
				'closed' => $row['closed'],
				'ignore' => $row['ignore_all'],
				'buttons' => array(
					'quickmod_check' => array(
						'checkbox' => !$context['view_closed'],
						'name' => 'close',
						'value' => $row['id_report'],
					),
					'details' => array(
						'href' => getUrl('action', ['action' => 'moderate', 'area' => $context['admin_area'], 'report' => $row['id_report']]),
						'text' => $txt['mc_reportedp_details'],
					),
					'ignore' => array(
						'href' => getUrl('action', ['action' => 'moderate', 'area' => $context['admin_area'], 'sa' => ($context['view_closed'] ? 'closed' : ''), 'ignore' => (int) !$row['ignore_all'], 'rid' => $row['id_report'], 'start' => $context['start'], '{session_data}']),
						'text' => $row['ignore_all'] ? $txt['mc_reportedp_unignore'] : $txt['mc_reportedp_ignore'],
						'custom' => $row['ignore_all'] ? '' : 'onclick="return confirm(' . JavaScriptEscape($txt['mc_reportedp_ignore_confirm']) . ');"',
					),
					'close' => array(
						'href' => getUrl('action', ['action' => 'moderate', 'area' => $context['admin_area'], 'sa' => ($context['view_closed'] ? 'closed' : ''), 'close' => (int) !$row['closed'], 'rid' => $row['id_report'], 'start' => $context['start'], '{session_data}']),
						'text' => $context['view_closed'] ? $txt['mc_reportedp_open'] : $txt['mc_reportedp_close'],
					),
				),
			);
			$report_boards_ids[] = $row['id_board'];
		}

		// Get the names of boards these topics are in.
		if (!empty($report_ids))
		{
			require_once(SUBSDIR . '/Boards.subs.php');
			$board_names = getBoardList(array('included_boards' => $report_boards_ids), true);

			// Add the board name to the report array
			foreach ($context['reports'] as $id_report => $report)
			{
				if (!empty($board_names[$report['board']]))
				{
					$context['reports'][$id_report]['board_name'] = $board_names[$report['board']]['board_name'];
				}
			}
		}

		// Now get all the people who reported it.
		if (!empty($report_ids))
		{
			$comments = getReportsUserComments($report_ids);
			foreach ($comments as $id_rep => $rows)
			{
				foreach ($rows as $row)
				{
					$context['reports'][$id_rep]['comments'][] = array(
						'id' => $row['id_comment'],
						'message' => $row['comment'],
						'raw_time' => $row['time_sent'],
						'time' => standardTime($row['time_sent']),
						'html_time' => htmlTime($row['time_sent']),
						'timestamp' => forum_time(true, $row['time_sent']),
						'member' => array(
							'id' => $row['id_member'],
							'name' => empty($row['reporter']) ? $txt['guest'] : $row['reporter'],
							'link' => $row['id_member'] ? ' 'profile', 'u' => $row['id_member']]) . '">' . $row['reporter'] . '' : (empty($row['reporter']) ? $txt['guest'] : $row['reporter']),
							'href' => $row['id_member'] ? getUrl('profile', ['action' => 'profile', 'u' => $row['id_member']]) : '',
						),
					);
				}
			}
		}
	}

	/**
	 * Get details about the moderation report
	 *
	 * - report is specified in the url param report.
	 */
	public function action_modReport()
	{
		global $context, $txt;

		// Have to at least give us something
		$report = $this->_req->getQuery('report', 'intval', 0);
		if (empty($report))
		{
			throw new Exception('mc_no_modreport_specified');
		}

		// This should not be needed...
		$show_pms = false;
		if ($context['admin_area'] === 'pm_reports')
		{
			$show_pms = true;
			isAllowedTo('admin_forum');
		}

		// Get the report details, need this so we can limit access to a particular board
		$row = modReportDetails($report, $show_pms);

		// So did we find anything?
		if ($row === false)
		{
			throw new Exception('mc_no_modreport_found');
		}

		// Woohoo we found a report and they can see it!  Bad news is we have more work to do
		// If they are adding a comment then... add a comment.
		if (isset($this->_req->post->add_comment) && !empty($this->_req->post->mod_comment))
		{
			checkSession();

			$newComment = trim(Util::htmlspecialchars($this->_req->post->mod_comment));

			// In it goes.
			if (!empty($newComment))
			{
				addReportComment($report, $newComment);

				// Redirect to prevent double submission.
				redirectexit('action=moderate;area=' . $context['admin_area'] . ';report=' . $report);
			}
		}

		$bbc_parser = ParserWrapper::instance();

		$context['report'] = array(
			'id' => $row['id_report'],
			'topic_id' => $row['id_topic'],
			'board_id' => $row['id_board'],
			'message_id' => $row['id_msg'],
			'message_href' => getUrl('action', ['msg' => $row['id_msg']]),
			'message_link' => ' $row['id_msg']]) . '">' . $row['subject'] . '',
			'report_href' => getUrl('action', ['action' => 'moderate', 'area' => $context['admin_area'], $context['admin_area'] => $row['id_report']]),
			'author' => array(
				'id' => $row['id_author'],
				'name' => $row['author_name'],
				'link' => $row['id_author'] ? ' 'profile', 'u' => $row['id_author']]) . '">' . $row['author_name'] . '' : $row['author_name'],
				'href' => getUrl('profile', ['action' => 'profile', 'u' => $row['id_author']]),
			),
			'comments' => array(),
			'mod_comments' => array(),
			'time_started' => standardTime($row['time_started']),
			'last_updated' => standardTime($row['time_updated']),
			'subject' => $row['subject'],
			'body' => $bbc_parser->parseReport($row['body']),
			'num_reports' => $row['num_reports'],
			'closed' => $row['closed'],
			'ignore' => $row['ignore_all']
		);

		// So what bad things do the reporters have to say about it?
		$comments = getReportsUserComments($context['report']['id']);
		foreach ($comments[$context['report']['id']] as $row)
		{
			$context['report']['comments'][] = array(
				'id' => $row['id_comment'],
				'message' => strtr($row['comment'], array("\n" => '
')),
				'time' => standardTime($row['time_sent']),
				'html_time' => htmlTime($row['time_sent']),
				'timestamp' => forum_time(true, $row['time_sent']),
				'member' => array(
					'id' => $row['id_member'],
					'name' => empty($row['reporter']) ? $txt['guest'] : $row['reporter'],
					'link' => $row['id_member'] ? ' 'profile', 'u' => $row['id_member']]) . '">' . $row['reporter'] . '' : (empty($row['reporter']) ? $txt['guest'] : $row['reporter']),
					'href' => $row['id_member'] ? getUrl('profile', ['action' => 'profile', 'u' => $row['id_member']]) : '',
					'ip' => !empty($row['member_ip']) && allowedTo('moderate_forum') ? ' 'trackip', 'searchip' => $row['member_ip']]) . '">' . $row['member_ip'] . '' : '',
				),
			);
		}

		// Hang about old chap, any comments from moderators on this one?
		$mod_comments = getReportModeratorsComments($context['report']['id']);
		foreach ($mod_comments as $row)
		{
			$context['report']['mod_comments'][] = array(
				'id' => $row['id_comment'],
				'message' => $bbc_parser->parseReport($row['body']),
				'time' => standardTime($row['log_time']),
				'html_time' => htmlTime($row['log_time']),
				'timestamp' => forum_time(true, $row['log_time']),
				'member' => array(
					'id' => $row['id_member'],
					'name' => $row['moderator'],
					'link' => $row['id_member'] ? ' 'profile', 'u' => $row['id_member']]) . '">' . $row['moderator'] . '' : $row['moderator'],
					'href' => getUrl('profile', ['action' => 'profile', 'u' => $row['id_member']]),
				),
			);
		}

		// What have the other moderators done to this message?
		require_once(SUBSDIR . '/Modlog.subs.php');
		\ElkArte\Themes\ThemeLoader::loadLanguageFile('Modlog');

		// This is all the information from the moderation log.
		$listOptions = array(
			'id' => 'moderation_actions_list',
			'title' => $txt['mc_modreport_modactions'],
			'items_per_page' => 15,
			'no_items_label' => $txt['modlog_no_entries_found'],
			'base_href' =>getUrl('action', ['action' => 'moderate', 'area' => $context['admin_area'], 'report' => $context['report']['id']]),
			'default_sort_col' => 'time',
			'get_items' => array(
				'function' => 'list_getModLogEntries',
				'params' => array(
					'lm.id_topic = {int:id_topic}',
					array('id_topic' => $context['report']['topic_id']),
					1,
				),
			),
			'get_count' => array(
				'function' => 'list_getModLogEntryCount',
				'params' => array(
					'lm.id_topic = {int:id_topic}',
					array('id_topic' => $context['report']['topic_id']),
					1,
				),
			),
			// This assumes we are viewing by user.
			'columns' => array(
				'action' => array(
					'header' => array(
						'value' => $txt['modlog_action'],
					),
					'data' => array(
						'db' => 'action_text',
						'class' => 'smalltext',
					),
					'sort' => array(
						'default' => 'lm.action',
						'reverse' => 'lm.action DESC',
					),
				),
				'time' => array(
					'header' => array(
						'value' => $txt['modlog_date'],
					),
					'data' => array(
						'db' => 'time',
						'class' => 'smalltext',
					),
					'sort' => array(
						'default' => 'lm.log_time',
						'reverse' => 'lm.log_time DESC',
					),
				),
				'moderator' => array(
					'header' => array(
						'value' => $txt['modlog_member'],
					),
					'data' => array(
						'db' => 'moderator_link',
						'class' => 'smalltext',
					),
					'sort' => array(
						'default' => 'mem.real_name',
						'reverse' => 'mem.real_name DESC',
					),
				),
				'position' => array(
					'header' => array(
						'value' => $txt['modlog_position'],
					),
					'data' => array(
						'db' => 'position',
						'class' => 'smalltext',
					),
					'sort' => array(
						'default' => 'mg.group_name',
						'reverse' => 'mg.group_name DESC',
					),
				),
				'ip' => array(
					'header' => array(
						'value' => $txt['modlog_ip'],
					),
					'data' => array(
						'db' => 'ip',
						'class' => 'smalltext',
					),
					'sort' => array(
						'default' => 'lm.ip',
						'reverse' => 'lm.ip DESC',
					),
				),
			),
		);

		// Create the watched user list.
		createList($listOptions);

		// Make sure to get the correct tab selected.
		if ($context['report']['closed'])
		{
			$context[$context['moderation_menu_name']]['current_subsection'] = 'closed';
		}

		// Finally we are done :P
		theme()->getTemplates()->load('ModerationCenter');
		if ($context['admin_area'] === 'pm_reports')
		{
			$context['page_title'] = sprintf($txt['mc_view_pmreport'], $context['report']['author']['name']);
			$context['section_title'] = sprintf($txt['mc_view_pmreport'], $context['report']['author']['link']);
			$context['section_descripion'] = sprintf($txt['mc_pmreport_summary'], $context['report']['num_reports'], $context['report']['last_updated']);
		}
		else
		{
			$context['page_title'] = sprintf($txt['mc_viewmodreport'], $context['report']['subject'], $context['report']['author']['name']);
			$context['section_title'] = sprintf($txt['mc_viewmodreport'], $context['report']['message_link'], $context['report']['author']['link']);
			$context['section_descripion'] = sprintf($txt['mc_modreport_summary'], $context['report']['num_reports'], $context['report']['last_updated']);
		}

		$context['sub_template'] = 'viewmodreport';
	}

	/**
	 * Change moderation preferences.
	 */
	public function action_moderationSettings()
	{
		global $context, $txt;

		// Some useful context stuff.
		theme()->getTemplates()->load('ModerationCenter');
		$context['page_title'] = $txt['mc_settings'];
		$context['sub_template'] = 'moderation_settings';
		$context[$context['moderation_menu_name']]['tab_data'] = array(
			'title' => $txt['mc_prefs_title'],
			'help' => '',
			'description' => $txt['mc_prefs_desc']
		);

		// What blocks can this user see?
		$context['homepage_blocks'] = array(
			'n' => $txt['mc_prefs_latest_news'],
			'p' => $txt['mc_notes'],
		);

		if ($context['can_moderate_groups'])
		{
			$context['homepage_blocks']['g'] = $txt['mc_group_requests'];
		}

		if ($context['can_moderate_boards'])
		{
			$context['homepage_blocks']['r'] = $txt['mc_reported_posts'];
			$context['homepage_blocks']['w'] = $txt['mc_watched_users'];
			$context['homepage_blocks']['a'] = $txt['mc_required'];
		}

		// Does the user have any settings yet?
		if (empty(User::$settings['mod_prefs']))
		{
			$mod_blocks = 'np' . ($context['can_moderate_boards'] ? 'wra' : '') . ($context['can_moderate_groups'] ? 'g' : '');
			$pref_binary = 5;
			$show_reports = 1;
		}
		else
		{
			list ($show_reports, $mod_blocks, $pref_binary) = explode('|', User::$settings['mod_prefs']);
		}

		// Are we saving?
		if (isset($this->_req->post->save))
		{
			checkSession('post');
			validateToken('mod-set');

			/* Current format of mod_prefs is:
				x|ABCD|yyy

				WHERE:
					x = Show report count on forum header.
					ABCD = Block indexes to show on moderation main page.
					yyy = Integer with the following bit status:
						- yyy & 1 = Always notify on reports.
						- yyy & 2 = Notify on reports for moderators only.
						- yyy & 4 = Notify about posts awaiting approval.
			*/

			// Do blocks first!
			$mod_blocks = '';
			if (!empty($this->_req->post->mod_homepage))
			{
				foreach ($this->_req->post->mod_homepage as $k => $v)
				{
					// Make sure they can add this...
					if (isset($context['homepage_blocks'][$k]))
					{
						$mod_blocks .= $k;
					}
				}
			}

			// Now check other options!
			$pref_binary = 0;

			if ($context['can_moderate_approvals'] && !empty($this->_req->post->mod_notify_approval))
			{
				$pref_binary |= 4;
			}

			if ($context['can_moderate_boards'])
			{
				if (!empty($this->_req->post->mod_notify_report))
				{
					$pref_binary |= ($this->_req->post->mod_notify_report == 2 ? 1 : 2);
				}

				$show_reports = !empty($this->_req->post->mod_show_reports) ? 1 : 0;
			}

			// Put it all together.
			$mod_prefs = $show_reports . '|' . $mod_blocks . '|' . $pref_binary;
			require_once(SUBSDIR . '/Members.subs.php');
			updateMemberData($this->user->id, array('mod_prefs' => $mod_prefs));
		}

		// What blocks does the user currently have selected?
		$context['mod_settings'] = array(
			'show_reports' => $show_reports,
			'notify_report' => $pref_binary & 2 ? 1 : ($pref_binary & 1 ? 2 : 0),
			'notify_approval' => $pref_binary & 4,
			'user_blocks' => str_split($mod_blocks),
		);

		createToken('mod-set');
	}

	/**
	 * View watched users and their posts
	 */
	public function action_viewWatchedUsers()
	{
		global $modSettings, $context, $txt;

		// Some important context!
		$context['page_title'] = $txt['mc_watched_users_title'];
		$context['view_posts'] = isset($this->_req->query->sa) && $this->_req->query->sa === 'post';
		$context['start'] = $this->_req->getQuery('start', 'intval', 0);

		theme()->getTemplates()->load('ModerationCenter');

		// Get some key settings!
		$modSettings['warning_watch'] = empty($modSettings['warning_watch']) ? 1 : $modSettings['warning_watch'];

		// Put some pretty tabs on cause we're gonna be doing hot stuff here...
		$context[$context['moderation_menu_name']]['tab_data'] = array(
			'title' => $txt['mc_watched_users_title'],
			'help' => '',
			'description' => $txt['mc_watched_users_desc'],
		);

		// First off - are we deleting?
		if (!empty($this->_req->query->delete) || !empty($this->_req->post->delete))
		{
			checkSession(isset($this->_req->query->delete) ? 'get' : 'post');

			// Clicked on remove or using checkboxes to multi delete
			$toDelete = array();
			if (isset($this->_req->query->delete))
			{
				$toDelete[] = (int) $this->_req->query->delete;
			}
			else
			{
				$toDelete = array_map('intval', $this->_req->post->delete);
			}

			if (!empty($toDelete))
			{
				$remover = new MessagesDelete($modSettings['recycle_enable'], $modSettings['recycle_board']);

				// If they don't have permission we'll let it error - either way no chance of a security slip here!
				foreach ($toDelete as $did)
				{
					$remover->removeMessage($did);
				}
			}
		}

		// Start preparing the list by grabbing relevant permissions.
		if (!$context['view_posts'])
		{
			$approve_query = '';
			$delete_boards = array();
		}
		else
		{
			// Still obey permissions!
			$approve_boards = !empty($this->user->mod_cache['ap']) ? $this->user->mod_cache['ap'] : boardsAllowedTo('approve_posts');
			$delete_boards = boardsAllowedTo('delete_any');

			if ($approve_boards == array(0))
			{
				$approve_query = '';
			}
			elseif (!empty($approve_boards))
			{
				$approve_query = ' AND m.id_board IN (' . implode(',', $approve_boards) . ')';
			}
			// Nada, zip, etc...
			else
			{
				$approve_query = ' AND 1=0';
			}
		}

		// This is all the information required for a watched user listing.
		$listOptions = array(
			'id' => 'watch_user_list',
			'title' => $txt['mc_watched_users_title'] . ' - ' . ($context['view_posts'] ? $txt['mc_watched_users_post'] : $txt['mc_watched_users_member']),
			'width' => '100%',
			'items_per_page' => $modSettings['defaultMaxMessages'],
			'no_items_label' => $context['view_posts'] ? $txt['mc_watched_users_no_posts'] : $txt['mc_watched_users_none'],
			'base_href' => getUrl('action', ['action' => 'moderate', 'area' => 'userwatch', 'sa' => ($context['view_posts'] ? 'post' : 'member')]),
			'default_sort_col' => $context['view_posts'] ? '' : 'member',
			'get_items' => array(
				'function' => $context['view_posts']
					? function ($start, $items_per_page, $sort, $approve_query, $delete_boards) {
						return $this->list_getWatchedUserPosts($start, $items_per_page, $sort, $approve_query, $delete_boards);
					}
					: function ($start, $items_per_page, $sort) {
						return $this->list_getWatchedUsers($start, $items_per_page, $sort);
					},
				'params' => array(
					$approve_query,
					$delete_boards,
				),
			),
			'get_count' => array(
				'function' => $context['view_posts']
					? function ($approve_query) {
						return $this->list_getWatchedUserPostsCount($approve_query);
					}
					: function () {
						return $this->list_getWatchedUserCount();
					},
				'params' => array(
					$approve_query,
				),
			),
			// This assumes we are viewing by user.
			'columns' => array(
				'member' => array(
					'header' => array(
						'value' => $txt['mc_watched_users_member'],
					),
					'data' => array(
						'sprintf' => array(
							'format' => ' 'profile', 'u' => '%1$d']) . '">%2$s',
							'params' => array(
								'id' => false,
								'name' => false,
							),
						),
					),
					'sort' => array(
						'default' => 'real_name',
						'reverse' => 'real_name DESC',
					),
				),
				'warning' => array(
					'header' => array(
						'value' => $txt['mc_watched_users_warning'],
					),
					'data' => array(
						'function' => function ($member) {
							return allowedTo('issue_warning') ? ' 'profile', 'area' => 'issuewarning', 'u' => $member['id']]) . '">' . $member['warning'] . '%' : $member['warning'] . '%';
						},
					),
					'sort' => array(
						'default' => 'warning',
						'reverse' => 'warning DESC',
					),
				),
				'posts' => array(
					'header' => array(
						'value' => $txt['posts'],
					),
					'data' => array(
						'sprintf' => array(
							'format' => ' 'profile', 'u' => '%1$d', 'area' => 'showposts', 'sa' => 'messages']) . '">%2$s',
							'params' => array(
								'id' => false,
								'posts' => false,
							),
						),
					),
					'sort' => array(
						'default' => 'posts',
						'reverse' => 'posts DESC',
					),
				),
				'last_login' => array(
					'header' => array(
						'value' => $txt['mc_watched_users_last_login'],
					),
					'data' => array(
						'db' => 'last_login',
					),
					'sort' => array(
						'default' => 'last_login',
						'reverse' => 'last_login DESC',
					),
				),
				'last_post' => array(
					'header' => array(
						'value' => $txt['mc_watched_users_last_post'],
					),
					'data' => array(
						'function' => function ($member) {
							if ($member['last_post_id'])
							{
								return ' $member['last_post_id']]) . '">' . $member['last_post'] . '';
							}

							return $member['last_post'];
						},
					),
				),
			),
			'form' => array(
				'href' => getUrl('action', ['action' => 'moderate', 'area' => 'userwatch', 'sa' => 'post']),
				'include_sort' => true,
				'include_start' => true,
				'hidden_fields' => array(
					$context['session_var'] => $context['session_id'],
				),
			),
			'additional_rows' => array(
				$context['view_posts'] ?
					array(
						'position' => 'below_table_data',
						'value' => '
						<input type="submit" name="delete_selected" value="' . $txt['quickmod_delete_selected'] . '" class="right_submit" />',
					) : array(),
			),
		);

		// If this is being viewed by posts we actually change the columns to call a template each time.
		if ($context['view_posts'])
		{
			$listOptions['columns'] = array(
				'posts' => array(
					'data' => array(
						'function' => function ($post) {
							return template_user_watch_post_callback($post);
						},
					),
				),
			);
		}

		// Create the watched user list.
		createList($listOptions);

		$context['sub_template'] = 'show_list';
		$context['default_list'] = 'watch_user_list';
	}

	/**
	 * Callback for createList().
	 *
	 * @param int $start The item to start with (for pagination purposes)
	 * @param int $items_per_page The number of items to show per page
	 * @param string $sort A string indicating how to sort the results
	 * @param string $approve_query
	 * @param int[] $delete_boards
	 *
	 * @return array
	 * @uses watchedUserPosts()
	 *
	 */
	public function list_getWatchedUserPosts($start, $items_per_page, $sort, $approve_query, $delete_boards)
	{
		// Watched users posts
		return watchedUserPosts($start, $items_per_page, $approve_query, $delete_boards);
	}

	/**
	 * Callback for createList() used in watched users
	 *
	 * @param int $start The item to start with (for pagination purposes)
	 * @param int $items_per_page The number of items to show per page
	 * @param string $sort A string indicating how to sort the results
	 *
	 * @return array
	 * @uses watchedUsers()
	 *
	 */
	public function list_getWatchedUsers($start, $items_per_page, $sort)
	{
		// Find all our watched users
		return watchedUsers($start, $items_per_page, $sort);
	}

	/**
	 * Callback for createList().
	 *
	 * @param string $approve_query
	 *
	 * @return int
	 * @uses watchedUserPostsCount()
	 *
	 */
	public function list_getWatchedUserPostsCount($approve_query)
	{
		global $modSettings;

		return watchedUserPostsCount($approve_query, $modSettings['warning_watch']);
	}

	/**
	 * Callback for createList() for watched users
	 *
	 * - returns count
	 *
	 * @uses watchedUserCount()
	 */
	public function list_getWatchedUserCount()
	{
		global $modSettings;

		return watchedUserCount($modSettings['warning_watch']);
	}

	/**
	 * Simply put, look at the warning log!
	 */
	public function action_viewWarningLog()
	{
		global $modSettings, $context, $txt;

		// Setup context as always.
		$context['page_title'] = $txt['mc_warning_log_title'];

		require_once(SUBSDIR . '/Moderation.subs.php');
		\ElkArte\Themes\ThemeLoader::loadLanguageFile('Modlog');

		// If we're coming in from a search, get the variables.
		if (!empty($this->_req->post->params) && empty($this->_req->post->is_search))
		{
			$search_params = base64_decode(strtr($this->_req->post->params, array(' ' => '+')));
			$search_params = @json_decode($search_params);
		}

		// This array houses all the valid search types.
		$searchTypes = array(
			'member' => array('sql' => 'mem.real_name', 'label' => $txt['profile_warning_previous_issued']),
			'recipient' => array('sql' => 'recipient_name', 'label' => $txt['mc_warnings_recipient']),
		);

		// Setup the allowed quick search type
		$context['order'] = isset($this->_req->query->sort) && isset($searchTypes[$this->_req->query->sort]) ? $this->_req->query->sort : 'member';

		if (!isset($search_params['string']) || (!empty($this->_req->post->search) && $search_params['string'] !== $this->_req->post->search))
		{
			$search_params_string = empty($this->_req->post->search) ? '' : $this->_req->post->search;
		}
		else
		{
			$search_params_string = $search_params['string'];
		}

		if (isset($this->_req->post->search_type) || empty($search_params['type']) || !isset($searchTypes[$search_params['type']]))
		{
			$search_params_type = isset($this->_req->post->search_type) && isset($searchTypes[$this->_req->post->search_type]) ? $this->_req->post->search_type : (isset($searchTypes[$context['order']]) ? $context['order'] : 'member');
		}
		else
		{
			$search_params_type = $search_params['type'];
		}

		$search_params_column = $searchTypes[$search_params_type]['sql'];
		$search_params = array(
			'string' => $search_params_string,
			'type' => $search_params_type,
		);

		// Setup the search context.
		$context['search_params'] = empty($search_params['string']) ? '' : base64_encode(json_encode($search_params));
		$context['search'] = array(
			'string' => $search_params['string'],
			'type' => $search_params['type'],
			'label' => $searchTypes[$search_params_type]['label'],
		);

		// This is all the information required for a watched user listing.
		$listOptions = array(
			'id' => 'warning_list',
			'title' => $txt['mc_warning_log_title'],
			'items_per_page' => $modSettings['defaultMaxMessages'],
			'no_items_label' => $txt['mc_warnings_none'],
			'base_href' => getUrl('action', ['action' => 'moderate', 'area' => 'warnings', 'sa' => 'log', '{session_data}']),
			'default_sort_col' => 'time',
			'get_items' => array(
				'function' => function ($start, $items_per_page, $sort, $query_string, $query_params) {
					return $this->list_getWarnings($start, $items_per_page, $sort, $query_string, $query_params);
				},
				'params' => array(
					(!empty($search_params['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : ''),
					array('sql_type' => $search_params_column, 'search_string' => $search_params['string']),
				),
			),
			'get_count' => array(
				'function' => function ($query_string, $query_params) {
					return $this->list_getWarningCount($query_string, $query_params);
				},
				'params' => array(
					(!empty($search_params['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : ''),
					array('sql_type' => $search_params_column, 'search_string' => $search_params['string']),
				),
			),
			// This assumes we are viewing by user.
			'columns' => array(
				'issuer' => array(
					'header' => array(
						'value' => $txt['profile_warning_previous_issued'],
					),
					'data' => array(
						'db' => 'issuer_link',
					),
					'sort' => array(
						'default' => 'member_name_col',
						'reverse' => 'member_name_col DESC',
					),
				),
				'recipient' => array(
					'header' => array(
						'value' => $txt['mc_warnings_recipient'],
					),
					'data' => array(
						'db' => 'recipient_link',
					),
					'sort' => array(
						'default' => 'recipient_name',
						'reverse' => 'recipient_name DESC',
					),
				),
				'time' => array(
					'header' => array(
						'value' => $txt['profile_warning_previous_time'],
					),
					'data' => array(
						'db' => 'time',
					),
					'sort' => array(
						'default' => 'lc.log_time DESC',
						'reverse' => 'lc.log_time',
					),
				),
				'reason' => array(
					'header' => array(
						'value' => $txt['profile_warning_previous_reason'],
					),
					'data' => array(
						'function' => function ($warning) {
							global $txt;

							$output = '

									' . $warning['reason'] . '

';

							// If a notice was sent, provide a link to it
							if (!empty($warning['id_notice']))
							{
								$output .= '
									 'moderate', 'area' => 'notice', 'nid' => $warning['id_notice']]) . '" onclick="window.open(this.href, \'\', \'scrollbars=yes,resizable=yes,width=480,height=320\');return false;" target="_blank" class="new_win" title="' . $txt['profile_warning_previous_notice'] . '">';
							}

							return $output;
						},
					),
				),
				'points' => array(
					'header' => array(
						'value' => $txt['profile_warning_previous_level'],
					),
					'data' => array(
						'db' => 'counter',
					),
				),
			),
			'form' => array(
				'href' => getUrl('action', ['action' => 'moderate', 'area' => 'warnings', 'sa' => 'log', 'sort' => $context['order']]),
				'include_sort' => true,
				'include_start' => true,
				'hidden_fields' => array(
					$context['session_var'] => $context['session_id'],
					'params' => $context['search_params']
				),
			),
			'additional_rows' => array(
				array(
					'class' => 'submitbutton',
					'position' => 'below_table_data',
					'value' => '
						' . $txt['modlog_search'] . ' (' . $txt['modlog_by'] . ': ' . $context['search']['label'] . ')
						<input type="text" name="search" size="18" value="' . Util::htmlspecialchars($context['search']['string']) . '" class="input_text" />
						<input type="submit" name="is_search" value="' . $txt['modlog_go'] . '" />',
				),
			),
		);

		// Create the watched user list.
		createList($listOptions);

		$context['sub_template'] = 'show_list';
		$context['default_list'] = 'warning_list';
	}

	/**
	 * Callback for createList()
	 *
	 * - Used to get all issued warnings in the system
	 *
	 * @param int $start The item to start with (for pagination purposes)
	 * @param int $items_per_page The number of items to show per page
	 * @param string $sort A string indicating how to sort the results
	 * @param string $query_string
	 * @param mixed[] $query_params
	 *
	 * @return array
	 * @uses warnings() function in moderation.subs
	 *
	 */
	public function list_getWarnings($start, $items_per_page, $sort, $query_string, $query_params)
	{
		return warnings($start, $items_per_page, $sort, $query_string, $query_params);
	}

	/**
	 * Callback for createList()
	 *
	 * - Get the total count of all current warnings
	 *
	 * @param string $query_string
	 * @param mixed[] $query_params
	 *
	 * @return int
	 * @uses warningCount() function in moderation.subs
	 *
	 */
	public function list_getWarningCount($query_string, $query_params)
	{
		return warningCount($query_string, $query_params);
	}

	/**
	 * View all the custom warning templates.
	 *
	 *  - Shows all the templates in the system
	 *  - Provides for actions to add or delete them
	 */
	public function action_viewWarningTemplates()
	{
		global $modSettings, $context, $txt;

		require_once(SUBSDIR . '/Moderation.subs.php');

		// Submitting a new one?
		if (isset($this->_req->post->add))
		{
			$this->action_modifyWarningTemplate();

			return true;
		}
		// Deleting and existing one
		elseif (isset($this->_req->post->delete) && !empty($this->_req->post->deltpl))
		{
			checkSession('post');
			validateToken('mod-wt');

			removeWarningTemplate($this->_req->post->deltpl);
		}

		// Setup context as always.
		$context['page_title'] = $txt['mc_warning_templates_title'];

		// This is all the information required for a watched user listing.
		$listOptions = array(
			'id' => 'warning_template_list',
			'title' => $txt['mc_warning_templates_title'],
			'items_per_page' => $modSettings['defaultMaxMessages'],
			'no_items_label' => $txt['mc_warning_templates_none'],
			'base_href' => getUrl('action', ['action' => 'moderate', 'area' => 'warnings', 'sa' => 'templates', '{session_data}']),
			'default_sort_col' => 'title',
			'get_items' => array(
				'function' => function ($start, $items_per_page, $sort, $template_type = 'warntpl') {
					return $this->list_getWarningTemplates($start, $items_per_page, $sort, $template_type);
				},
			),
			'get_count' => array(
				'function' => function ($template_type = 'warntpl') {
					return $this->list_getWarningTemplateCount($template_type);
				},
			),
			'columns' => array(
				'title' => array(
					'header' => array(
						'value' => $txt['mc_warning_templates_name'],
					),
					'data' => array(
						'sprintf' => array(
							'format' => ' 'moderate', 'area' => 'warnings', 'sa' => 'templateedit', 'tid' => '%1$d']) . '">%2$s',
							'params' => array(
								'id_comment' => false,
								'title' => false,
								'body' => false,
							),
						),
					),
					'sort' => array(
						'default' => 'template_title',
						'reverse' => 'template_title DESC',
					),
				),
				'creator' => array(
					'header' => array(
						'value' => $txt['mc_warning_templates_creator'],
					),
					'data' => array(
						'db' => 'creator',
					),
					'sort' => array(
						'default' => 'creator_name',
						'reverse' => 'creator_name DESC',
					),
				),
				'time' => array(
					'header' => array(
						'value' => $txt['mc_warning_templates_time'],
					),
					'data' => array(
						'db' => 'time',
					),
					'sort' => array(
						'default' => 'lc.log_time DESC',
						'reverse' => 'lc.log_time',
					),
				),
				'delete' => array(
					'header' => array(
						'value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />',
						'style' => 'width: 4%;text-align: center;',
					),
					'data' => array(
						'function' => function ($rowData) {
							return '<input type="checkbox" name="deltpl[]" value="' . $rowData['id_comment'] . '" class="input_check" />';
						},
						'class' => 'centertext',
					),
				),
			),
			'form' => array(
				'href' => getUrl('action', ['action' => 'moderate', 'area' => 'warnings', 'sa' => 'templates']),
				'token' => 'mod-wt',
			),
			'additional_rows' => array(
				array(
					'position' => 'below_table_data',
					'value' => '
						<input type="submit" name="delete" value="' . $txt['mc_warning_template_delete'] . '" onclick="return confirm(\'' . $txt['mc_warning_template_delete_confirm'] . '\');" class="right_submit" />
						<input type="submit" name="add" value="' . $txt['mc_warning_template_add'] . '" class="right_submit" />',
				),
			),
		);

		// Create the watched user list.
		createToken('mod-wt');
		createList($listOptions);

		$context['sub_template'] = 'show_list';
		$context['default_list'] = 'warning_template_list';
	}

	/**
	 * Edit a warning template.
	 *
	 * @uses template_warn_template()
	 */
	public function action_modifyWarningTemplate()
	{
		global $context, $txt;

		require_once(SUBSDIR . '/Moderation.subs.php');
		loadJavascriptFile('admin.js', array(), 'admin_scripts');

		$context['id_template'] = $this->_req->getQuery('tid', 'intval', 0);
		$context['is_edit'] = $context['id_template'];

		// Standard template things.
		$context['page_title'] = $context['is_edit'] ? $txt['mc_warning_template_modify'] : $txt['mc_warning_template_add'];
		$context['sub_template'] = 'warn_template';
		$context[$context['moderation_menu_name']]['current_subsection'] = 'templates';

		// Defaults.
		$context['template_data'] = array(
			'title' => '',
			'body' => $txt['mc_warning_template_body_default'],
			'personal' => false,
			'can_edit_personal' => true,
		);

		// If it's an edit load it.
		if ($context['is_edit'])
		{
			modLoadTemplate($context['id_template']);
		}

		// Wait, we are saving?
		if (isset($this->_req->post->save))
		{
			checkSession('post');
			validateToken('mod-wt');

			// To check the BBC is pretty good...
			require_once(SUBSDIR . '/Post.subs.php');

			// Bit of cleaning!
			$template_body = trim($this->_req->post->template_body);
			$template_title = trim($this->_req->post->template_title);

			// Need something in both boxes.
			if (!empty($template_body) && !empty($template_title))
			{
				// Safety first.
				$template_title = Util::htmlspecialchars($template_title);

				// Clean up BBC.
				preparsecode($template_body);

				// But put line breaks back!
				$template_body = strtr($template_body, array('
' => "\n"));

				// Is this personal?
				$recipient_id = !empty($this->_req->post->make_personal) ? $this->user->id : 0;

				// If we are this far it's save time.
				if ($context['is_edit'])
				{
					// Simple update...
					modAddUpdateTemplate($recipient_id, $template_title, $template_body, $context['id_template']);

					// If it wasn't visible and now is they've effectively added it.
					if ($context['template_data']['personal'] && !$recipient_id)
					{
						logAction('add_warn_template', array('template' => $template_title));
					}
					// Conversely if they made it personal it's a delete.
					elseif (!$context['template_data']['personal'] && $recipient_id)
					{
						logAction('delete_warn_template', array('template' => $template_title));
					}
					// Otherwise just an edit.
					else
					{
						logAction('modify_warn_template', array('template' => $template_title));
					}
				}
				else
				{
					modAddUpdateTemplate($recipient_id, $template_title, $template_body, $context['id_template'], false);
					logAction('add_warn_template', array('template' => $template_title));
				}

				// Get out of town...
				redirectexit('action=moderate;area=warnings;sa=templates');
			}
			else
			{
				$context['warning_errors'] = array();
				$context['template_data']['title'] = !empty($template_title) ? $template_title : '';
				$context['template_data']['body'] = !empty($template_body) ? $template_body : $txt['mc_warning_template_body_default'];
				$context['template_data']['personal'] = !empty($this->_req->post->make_personal);

				if (empty($template_title))
				{
					$context['warning_errors'][] = $txt['mc_warning_template_error_no_title'];
				}

				if (empty($template_body))
				{
					$context['warning_errors'][] = $txt['mc_warning_template_error_no_body'];
				}
			}
		}

		createToken('mod-wt');
	}

	/**
	 * Callback for createList() to get all the templates of a type from the system
	 *
	 * @param int $start The item to start with (for pagination purposes)
	 * @param int $items_per_page The number of items to show per page
	 * @param string $sort A string indicating how to sort the results
	 * @param string $template_type type of template to load
	 *
	 * @return array
	 * @uses warningTemplates()
	 *
	 */
	public function list_getWarningTemplates($start, $items_per_page, $sort, $template_type = 'warntpl')
	{
		return warningTemplates($start, $items_per_page, $sort, $template_type);
	}

	/**
	 * Callback for createList() to get the number of templates of a type in the system
	 *
	 * @param string $template_type
	 *
	 * @return
	 * @uses warningTemplateCount()
	 *
	 */
	public function list_getWarningTemplateCount($template_type = 'warntpl')
	{
		return warningTemplateCount($template_type);
	}

	/**
	 * Entry point for viewing warning related stuff.
	 */
	public function action_viewWarnings()
	{
		global $context, $txt;

		// Some of this stuff is overseas, so to speak.
		theme()->getTemplates()->load('ModerationCenter');
		\ElkArte\Themes\ThemeLoader::loadLanguageFile('Profile');

		$subActions = array(
			'log' => array($this, 'action_viewWarningLog'),
			'templateedit' => array($this, 'action_modifyWarningTemplate', 'permission' => 'issue_warning'),
			'templates' => array($this, 'action_viewWarningTemplates', 'permission' => 'issue_warning'),
		);

		// Setup the admin tabs.
		$context[$context['moderation_menu_name']]['tab_data'] = array(
			'title' => $txt['mc_warnings'],
			'description' => $txt['mc_warnings_description'],
		);

		// Call the right function.
		$action = new Action('moderation_center');
		$subAction = $action->initialize($subActions, 'log');
		$context['sub_action'] = $subAction;
		$action->dispatch($subAction);
	}

	/**
	 * Show a list of all the group requests they can see.
	 * Checks permissions for group moderation.
	 */
	public function block_groupRequests()
	{
		global $context;

		// Make sure they can even moderate someone!
		if ($this->user->mod_cache['gq'] === '0=1')
		{
			return 'group_requests_block';
		}

		$context['group_requests'] = groupRequests();

		return 'group_requests_block';
	}

	/**
	 * Just prepares the time stuff for the latest news.
	 */
	public function block_latestNews()
	{
		global $context;

		$context['time_format'] = urlencode($this->user->time_format);

		// Return the template to use.
		return 'latest_news';
	}

	/**
	 * Show a list of the most active watched users.
	 */
	public function block_watchedUsers()
	{
		global $context;

		$watched_users = basicWatchedUsers();

		$context['watched_users'] = array();
		if (is_array($watched_users) || is_object($watched_users))
		{
			foreach ($watched_users as $user)
			{
				$context['watched_users'][] = array(
					'id' => $user['id_member'],
					'name' => $user['real_name'],
					'link' => ' 'profile', 'u' => $user['id_member']]) . '">' . $user['real_name'] . '',
					'href' => getUrl('profile', ['action' => 'profile', 'u' => $user['id_member']]),
					'last_login' => !empty($user['last_login']) ? standardTime($user['last_login']) : '',
				);
			}
		}

		return 'watched_users';
	}

	/**
	 * Shows a list of items requiring moderation action
	 * Includes post, topic, attachment, group, member and PBE values with links to each
	 */
	public function block_actionRequired()
	{
		global $context;

		// Get the action totals
		$mod_totals = loadModeratorMenuCounts();

		// This blocks total is only these fields
		$context['mc_required'] = $mod_totals['attachments'] + $mod_totals['emailmod'] + $mod_totals['topics'] + $mod_totals['posts'] + $mod_totals['memberreq'] + $mod_totals['groupreq'] + +$mod_totals['reports'];
		unset($mod_totals['postmod'], $mod_totals['pt_total'], $mod_totals['mg_total'], $mod_totals['grand_total']);
		$context['required'] = $mod_totals;

		// Links to the areas
		$context['links'] = array(
			'attachments' => '?action=moderate;area=attachmod;sa=attachments',
			'emailmod' => '?action=admin;area=maillist;sa=emaillist',
			'topics' => '?action=moderate;area=postmod;sa=topics',
			'posts' => '?action=moderate;area=postmod;sa=posts',
			'memberreq' => '?action=admin;area=viewmembers;sa=browse;type=approve',
			'groupreq' => '?action=moderate;area=groups;sa=requests',
			'reports' => '?action=moderate;area=reports;sa=open',
			'pm_reports' => '?action=moderate;area=pm_reports;sa=open',
		);

		return 'action_required';
	}

	/**
	 * Show an area for the moderator to type into.
	 */
	public function block_notes()
	{
		global $context, $txt;

		// Are we saving a note?
		if (isset($this->_req->post->makenote) && isset($this->_req->post->new_note))
		{
			checkSession();

			$new_note = Util::htmlspecialchars(trim($this->_req->post->new_note));

			// Make sure they actually entered something.
			if (!empty($new_note) && $new_note !== $txt['mc_click_add_note'])
			{
				// Insert it into the database then!
				addModeratorNote($this->user->id, $this->user->name, $new_note);

				// Clear the cache.
				Cache::instance()->remove('moderator_notes');
				Cache::instance()->remove('moderator_notes_total');
			}

			// Redirect otherwise people can resubmit.
			redirectexit('action=moderate');
		}

		// Bye... bye...
		if (isset($this->_req->query->notes) && isset($this->_req->query->delete) && is_numeric($this->_req->query->delete))
		{
			checkSession('get');

			// Just checkin'!
			$id_delete = (int) $this->_req->query->delete;

			// Lets delete it.
			removeModeratorNote($id_delete);

			// Clear the cache.
			Cache::instance()->remove('moderator_notes');
			Cache::instance()->remove('moderator_notes_total');

			redirectexit('action=moderate');
		}

		// How many notes in total?
		$moderator_notes_total = countModeratorNotes();

		// Grab the current notes. We can only use the cache for the first page of notes.
		$offset = isset($this->_req->query->notes) && isset($this->_req->query->start) ? $this->_req->query->start : 0;
		$moderator_notes = moderatorNotes($offset);

		// Lets construct a page index.
		$context['page_index'] = constructPageIndex('{scripturl}?action=moderate;area=index;notes', $this->_req->query->start, $moderator_notes_total, 10);
		$context['start'] = $this->_req->query->start;

		$bbc_parser = ParserWrapper::instance();

		$context['notes'] = array();
		foreach ($moderator_notes as $note)
		{
			$context['notes'][] = array(
				'author' => array(
					'id' => $note['id_member'],
					'link' => $note['id_member'] ? (' 'profile', 'u' => $note['id_member']]) . '" title="' . $txt['on'] . ' ' . strip_tags(standardTime($note['log_time'])) . '">' . $note['member_name'] . '') : $note['member_name'],
				),
				'time' => standardTime($note['log_time']),
				'html_time' => htmlTime($note['log_time']),
				'timestamp' => forum_time(true, $note['log_time']),
				'text' => $bbc_parser->parseReport($note['body']),
				'delete_href' => getUrl('action', ['action' => 'moderate', 'area' => 'index', 'notes' => 'delete=' . $note['id_note'], '{session_data}']),
			);
		}

		return 'notes';
	}

	/**
	 * Show a list of the most recent reported posts.
	 */
	public function block_reportedPosts()
	{
		global $context;

		if ($this->user->mod_cache['bq'] === '0=1')
		{
			return 'reported_posts_block';
		}

		$context['reported_posts'] = array();

		$reported_posts = reportedPosts(false);
		foreach ($reported_posts as $i => $row)
		{
			$context['reported_posts'][] = array(
				'id' => $row['id_report'],
				'alternate' => $i % 2,
				'topic_href' => getUrl('topic', ['topic' => $row['id_topic'], 'msg' => $row['id_msg'], 'start' => $row['id_msg'], 'hash' => '#msg' . $row['id_msg']]),
				'report_href' => getUrl('action', ['action' => 'moderate', 'area' =>  $context['admin_area'], 'report' => $row['id_report']]),
				'author' => array(
					'id' => $row['id_author'],
					'name' => $row['author_name'],
					'link' => $row['id_author'] ? ' 'profile', 'u' => $row['id_author']]) . '">' . $row['author_name'] . '' : $row['author_name'],
					'href' => getUrl('profile', ['action' => 'profile', 'u' => $row['id_author']]),
				),
				'comments' => array(),
				'subject' => $row['subject'],
				'num_reports' => $row['num_reports'],
			);
		}

		return 'reported_posts_block';
	}
}


text:
/*jslint browser: true, devel: true, node: true, ass: true, nomen: true, unparam: true, indent: 4 */

/**
 * @license
 * Copyright (c) 2015 The ExpandJS authors. All rights reserved.
 * This code may only be used under the BSD style license found at https://expandjs.github.io/LICENSE.txt
 * The complete set of authors may be found at https://expandjs.github.io/AUTHORS.txt
 * The complete set of contributors may be found at https://expandjs.github.io/CONTRIBUTORS.txt
 */
(function () {
    "use strict";

    var assertArgument = require('../assert/assertArgument'),
        createElement  = require('../dom/createElement'),
        getAttributes  = require('../dom/getAttributes'),
        getChildren    = require('../dom/getChildren'),
        isElement      = require('../tester/isElement'),
        isString       = require('../tester/isString'),
        isVoid         = require('../tester/isVoid'),
        replaceNode    = require('../dom/replaceNode');

    /**
     * Creates a new element from an existing one, with a new name, and returns it.
     *
     * ```html
     *      <div id="target" class="foo" bar>
     *          <span>Inner text.</span>
     *      </div>
     *
     *      <script>
     *          var el = document.querySelector('#target');
     *
     *          XP.renameElement(el, 'span');
     *          // => <span id="target" class="foo" bar>
     *                    <span>Inner text.</span>
     *                </span>
     *
     *          console.log(el);
     *          // => <span id="target" class="foo" bar>
     *                    <span>Inner text.</span>
     *                </span>
     *      </script>
     * ```
     *
     * @function renameElement
     * @param {Element} [element] The element to modify
     * @param {string} [name] The new name of the element
     * @returns {Element | undefined} Returns the newly created element
     */
    module.exports = function renameElement(element, name) {
        assertArgument(isVoid(element) || isElement(element), 1, 'Element');
        assertArgument(isVoid(name) || isString(name), 2, 'string');
        var target = element && name ? createElement(name, {attributes: getAttributes(element), children: getChildren(element)}) : undefined;
        if (target) { replaceNode(element, target); }
        return target || element;
    };

}());

redpajama_set_name: RedPajamaGithub


text:
"""
.. moduleauthor:: Gabriel Martin Becedillas Ruiz <gabriel.becedillas@gmail.com>
"""

from pyalgotrade import broker
from pyalgotrade.broker import backtesting
from pyalgotrade.bitstamp import common
from pyalgotrade.bitstamp import livebroker

LiveBroker = livebroker.LiveBroker

# In a backtesting or paper-trading scenario the BacktestingBroker dispatches events while processing events from the
# BarFeed.
# It is guaranteed to process BarFeed events before the strategy because it connects to BarFeed events before the
# strategy.

class BacktestingBroker(backtesting.Broker):
    MIN_TRADE_USD = 5

    """A Bitstamp backtesting broker.

    :param cash: The initial amount of cash.
    :type cash: int/float.
    :param barFeed: The bar feed that will provide the bars.
    :type barFeed: :class:`pyalgotrade.barfeed.BarFeed`
    :param fee: The fee percentage for each order. Defaults to 0.25%.
    :type fee: float.

    .. note::
        * Only limit orders are supported.
        * Orders are automatically set as **goodTillCanceled=True** and  **allOrNone=False**.
        * BUY_TO_COVER orders are mapped to BUY orders.
        * SELL_SHORT orders are mapped to SELL orders.
    """

    def __init__(self, cash, barFeed, fee=0.0025):
        commission = backtesting.TradePercentage(fee)
        backtesting.Broker.__init__(self, cash, barFeed, commission)

    def getInstrumentTraits(self, instrument):
        return common.BTCTraits()

    def submitOrder(self, order):
        if order.isInitial():
            # Override user settings based on Bitstamp limitations.
            order.setAllOrNone(False)
            order.setGoodTillCanceled(True)
        return backtesting.Broker.submitOrder(self, order)

    def createMarketOrder(self, action, instrument, quantity, onClose=False):
        raise Exception("Market orders are not supported")

    def createLimitOrder(self, action, instrument, limitPrice, quantity):
        if instrument != common.btc_symbol:
            raise Exception("Only BTC instrument is supported")

        if action == broker.Order.Action.BUY_TO_COVER:
            action = broker.Order.Action.BUY
        elif action == broker.Order.Action.SELL_SHORT:
            action = broker.Order.Action.SELL

        if limitPrice * quantity < BacktestingBroker.MIN_TRADE_USD:
            raise Exception("Trade must be >= %s" % (BacktestingBroker.MIN_TRADE_USD))

        if action == broker.Order.Action.BUY:
            # Check that there is enough cash.
            fee = self.getCommission().calculate(None, limitPrice, quantity)
            cashRequired = limitPrice * quantity + fee
            if cashRequired > self.getCash(False):
                raise Exception("Not enough cash")
        elif action == broker.Order.Action.SELL:
            # Check that there are enough coins.
            if quantity > self.getShares(common.btc_symbol):
                raise Exception("Not enough %s" % (common.btc_symbol))
        else:
            raise Exception("Only BUY/SELL orders are supported")

        return backtesting.Broker.createLimitOrder(self, action, instrument, limitPrice, quantity)

    def createStopOrder(self, action, instrument, stopPrice, quantity):
        raise Exception("Stop orders are not supported")

    def createStopLimitOrder(self, action, instrument, stopPrice, limitPrice, quantity):
        raise Exception("Stop limit orders are not supported")

class PaperTradingBroker(BacktestingBroker):
    """A Bitstamp paper trading broker.

    :param cash: The initial amount of cash.
    :type cash: int/float.
    :param barFeed: The bar feed that will provide the bars.
    :type barFeed: :class:`pyalgotrade.barfeed.BarFeed`
    :param fee: The fee percentage for each order. Defaults to 0.5%.
    :type fee: float.

    .. note::
        * Only limit orders are supported.
        * Orders are automatically set as **goodTillCanceled=True** and  **allOrNone=False**.
        * BUY_TO_COVER orders are mapped to BUY orders.
        * SELL_SHORT orders are mapped to SELL orders.
    """

    pass


text:
static int16_t png_min_sample = INT16_MAX;
static int16_t png_max_sample = INT16_MIN;
static float y_range = (float)INT16_MAX - (float)INT16_MIN;
static float y_half_range = (float)INT16_MAX;
static int image_bound_y;
static int png_x = 0;
static png_bytep *row_pointers;
static png_byte color_bg[4] = {0, 0, 0, 0};
static png_byte color_center[4] = {0, 0, 0, 255};
static png_byte color_outer[4] = {0, 0, 0, 255};
static png_bytep color_at_pix;
static int png_width = 256;
static int png_height = 64;
static int png_frames_per_pixel;
static int png_frames_until_emit;

// transcoding stuff
static FILE *transcode_out_f = NULL;
static struct GrooveEncoder *encoder = NULL;

static int version() {
    printf("3.0.1\n");
    return 0;
}

static int usage(const char *exe) {
    fprintf(stderr, "\
\n\
Usage:\n\
\n\
waveform [options] in [--transcode out] [--waveformjs out] [--png out]\n\
(where `in` is a file path and `out` is a file path or `-` for STDOUT)\n\
\n\
Options:\n\
--scan                       duration scan (default off)\n\
\n\
Transcoding Options:\n\
--bitrate 320                audio bitrate in kbps\n\
--format name                e.g. mp3, ogg, mp4\n\
--codec name                 e.g. mp3, vorbis, flac, aac\n\
--mime mimetype              e.g. audio/vorbis\n\
--tag-artist artistname      artist tag\n\
--tag-title title            title tag\n\
--tag-year 2000              year tag\n\
--tag-comment comment        comment tag\n\
\n\
WaveformJs Options:\n\
--wjs-width 800              width in samples\n\
--wjs-precision 4            how many digits of precision\n\
--wjs-plain                  exclude metadata in output JSON (default off)\n\
\n\
PNG Options:\n\
--png-width 256              width of the image\n\
--png-height 64              height of the image\n\
--png-color-bg 00000000      bg color, rrggbbaa\n\
--png-color-center 000000ff  gradient center color, rrggbbaa\n\
--png-color-outer 000000ff   gradient outer color, rrggbbaa\n\
\n");

    return 1;
}

static void *encode_write_thread(void *arg) {
    struct GrooveBuffer *buffer;

    while (groove_encoder_buffer_get(encoder, &buffer, 1) == GROOVE_BUFFER_YES) {
        fwrite(buffer->data[0], 1, buffer->size, transcode_out_f);
        groove_buffer_unref(buffer);
    }
    return NULL;
}

static int16_t int16_abs(int16_t x) {
    return x < 0 ? -x : x;
}

static int double_ceil(double x) {
    int n = x;
    return (x == (double)n) ? n : n + 1;
}

static void parseColor(const char * hex_str, png_bytep color) {
    unsigned long value = strtoul(hex_str, NULL, 16);
    color[3] = value & 0xff; value >>= 8;
    color[2] = value & 0xff; value >>= 8;
    color[1] = value & 0xff; value >>= 8;
    color[0] = value & 0xff;
}

static void emit_png_column() {
    // translate into y pixel coord.
    float float_min_sample = (float)png_min_sample;
    float float_max_sample = (float)png_max_sample;
    int y_min = ((float_min_sample + y_half_range) / y_range) * image_bound_y;
    int y_max = ((float_max_sample + y_half_range) / y_range) * image_bound_y;

    int y = 0;
    int four_x = 4 * png_x;

    // top bg
    for (; y < y_min; ++y) {
        memcpy(row_pointers[y] + four_x, color_bg, 4);
    }
    // top and bottom wave
    for (; y <= y_max; ++y) {
        memcpy(row_pointers[y] + four_x, color_at_pix + 4*y, 4);
    }
    // bottom bg
    for (; y < png_height; ++y) {
        memcpy(row_pointers[y] + four_x, color_bg, 4);
    }

    png_x += 1;
    png_frames_until_emit = png_frames_per_pixel;
    png_max_sample = INT16_MIN;
    png_min_sample = INT16_MAX;
}

int main(int argc, char * argv[]) {
    // arg parsing
    char *exe = argv[0];

    char *input_filename = NULL;
    char *transcode_output = NULL;
    char *waveformjs_output = NULL;
    char *png_output = NULL;

    int bit_rate_k = 320;
    char *format = NULL;
    char *codec = NULL;
    char *mime = NULL;
    char *tag_artist = NULL;
    char *tag_title = NULL;
    char *tag_year = NULL;
    char *tag_comment = NULL;

    int wjs_width = 800;
    int wjs_precision = 4;
    int wjs_plain = 0;

    int scan = 0;

    int i;
    for (i = 1; i < argc; ++i) {
        char *arg = argv[i];
        if (arg[0] == '-' && arg[1] == '-') {
            arg += 2;
            if (strcmp(arg, "scan") == 0) {
                scan = 1;
            } else if (strcmp(arg, "wjs-plain") == 0) {
                wjs_plain = 1;
            } else if (strcmp(arg, "version") == 0) {
                return version();
            } else if (i + 1 >= argc) {
                // args that take 1 parameter
                return usage(exe);
            } else if (strcmp(arg, "png") == 0) {
                png_output = argv[++i];
            } else if (strcmp(arg, "png-width") == 0) {
                png_width = atoi(argv[++i]);
            } else if (strcmp(arg, "png-height") == 0) {
                png_height = atoi(argv[++i]);
            } else if (strcmp(arg, "png-color-bg") == 0) {
                parseColor(argv[++i], color_bg);
            } else if (strcmp(arg, "png-color-center") == 0) {
                parseColor(argv[++i], color_center);
            } else if (strcmp(arg, "png-color-outer") == 0) {
                parseColor(argv[++i], color_outer);
            } else if (strcmp(arg, "bitrate") == 0) {
                bit_rate_k = atoi(argv[++i]);
            } else if (strcmp(arg, "format") == 0) {
                format = argv[++i];
            } else if (strcmp(arg, "codec") == 0) {
                codec = argv[++i];
            } else if (strcmp(arg, "mime") == 0) {
                mime = argv[++i];
            } else if (strcmp(arg, "transcode") == 0) {
                transcode_output = argv[++i];
            } else if (strcmp(arg, "waveformjs") == 0) {
                waveformjs_output = argv[++i];
            } else if (strcmp(arg, "tag-artist") == 0) {
                tag_artist = argv[++i];
            } else if (strcmp(arg, "tag-title") == 0) {
                tag_title = argv[++i];
            } else if (strcmp(arg, "tag-year") == 0) {
                tag_year = argv[++i];
            } else if (strcmp(arg, "tag-comment") == 0) {
                tag_comment = argv[++i];
            } else if (strcmp(arg, "wjs-width") == 0) {
                wjs_width = atoi(argv[++i]);
            } else if (strcmp(arg, "wjs-precision") == 0) {
                wjs_precision = atoi(argv[++i]);
            } else {
                fprintf(stderr, "Unrecognized argument: %s\n", arg);
                return usage(exe);
            }
        } else if (!input_filename) {
            input_filename = arg;
        } else {
            fprintf(stderr, "Unexpected parameter: %s\n", arg);
            return usage(exe);
        }
    }

    if (!input_filename) {
        fprintf(stderr, "input file parameter required\n");
        return usage(exe);
    }

    if (!transcode_output && !waveformjs_output && !png_output) {
        fprintf(stderr, "at least one output required\n");
        return usage(exe);
    }

    // arg parsing done. let's begin.

    groove_init();
    atexit(groove_finish);

    struct GrooveFile *file = groove_file_open(input_filename);
    if (!file) {
        fprintf(stderr, "Error opening input file: %s\n", input_filename);
        return 1;
    }
    struct GroovePlaylist *playlist = groove_playlist_create();
    groove_playlist_set_fill_mode(playlist, GROOVE_ANY_SINK_FULL);

    struct GrooveSink *sink = groove_sink_create();
    sink->audio_format.sample_rate = 44100;
    sink->audio_format.channel_layout = GROOVE_CH_LAYOUT_STEREO;
    sink->audio_format.sample_fmt = GROOVE_SAMPLE_FMT_S16;

    if (groove_sink_attach(sink, playlist) < 0) {
        fprintf(stderr, "error attaching sink\n");
        return 1;
    }

    struct GrooveBuffer *buffer;
    int frame_count;

    // scan the song for the exact correct frame count and duration
    float duration;
    if (scan) {
        struct GroovePlaylistItem *item = groove_playlist_insert(playlist, file, 1.0, 1.0, NULL);
        frame_count = 0;
        while (groove_sink_buffer_get(sink, &buffer, 1) == GROOVE_BUFFER_YES) {
            frame_count += buffer->frame_count;
            groove_buffer_unref(buffer);
        }
        groove_playlist_remove(playlist, item);
        duration = frame_count / 44100.0f;
    } else {
        duration = groove_file_duration(file);
        frame_count = double_ceil(duration * 44100.0);
    }

    pthread_t thread_id;
    if (transcode_output) {
        if (strcmp(transcode_output, "-") == 0) {
            transcode_out_f = stdout;
        } else {
            transcode_out_f = fopen(transcode_output, "wb");
            if (!transcode_out_f) {
                fprintf(stderr, "Error opening output file %s\n", transcode_output);
                return 1;
            }
        }

        encoder = groove_encoder_create();
        encoder->bit_rate = bit_rate_k * 1000;
        encoder->format_short_name = format;
        encoder->codec_short_name = codec;
        encoder->filename = transcode_output;
        encoder->mime_type = mime;
        if (tag_artist)
            groove_encoder_metadata_set(encoder, "artist", tag_artist, 0);
        if (tag_title)
            groove_encoder_metadata_set(encoder, "title", tag_title, 0);
        if (tag_year)
            groove_encoder_metadata_set(encoder, "year", tag_year, 0);
        if (tag_comment)
            groove_encoder_metadata_set(encoder, "comment", tag_comment, 0);

        encoder->target_audio_format.sample_rate = 44100;
        encoder->target_audio_format.channel_layout = GROOVE_CH_LAYOUT_STEREO;
        encoder->target_audio_format.sample_fmt = GROOVE_SAMPLE_FMT_S16;

        if (groove_encoder_attach(encoder, playlist) < 0) {
            fprintf(stderr, "error attaching encoder\n");
            return 1;
        }

        // this thread pops encoded audio buffers from the sink and writes them
        // to the output
        // we'll use the main thread for waveformjs/png output
        pthread_create(&thread_id, NULL, encode_write_thread, NULL);
    }

    // insert the item *after* creating the sinks to avoid race conditions
    groove_playlist_insert(playlist, file, 1.0, 1.0, NULL);

    int png_center_y;
    double png_center_y_float;
    FILE *png_file = NULL;
    png_structp png = NULL;
    png_infop png_info = NULL;
    if (png_output) {
        png_frames_per_pixel = frame_count / png_width;
        if (png_frames_per_pixel < 1) png_frames_per_pixel = 1;

        png_center_y = png_height / 2;
        png_center_y_float = (double) png_center_y;

        png_frames_until_emit = png_frames_per_pixel;

        if (strcmp(png_output, "-") == 0) {
            png_file = stdout;
        } else {
            png_file = fopen(png_output, "wb");
            if (!png_file) {
                fprintf(stderr, "Unable to open %s for writing\n", png_output);
                return 1;
            }
        }

        png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
        if (!png) {
            fprintf(stderr, "Unable to allocate png write structure\n");
            return 1;
        }

        png_info = png_create_info_struct(png);

        if (! png_info) {
            fprintf(stderr, "Unable to allocate png info structure\n");
            return 1;
        }

        png_init_io(png, png_file);

        png_set_IHDR(png, png_info, png_width, png_height, 8,
            PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

        png_write_info(png, png_info);

        // allocate memory to write to png file
        row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * png_height);

        if (! row_pointers) {
            fprintf(stderr, "Out of memory.\n");
            return 1;
        }

        color_at_pix = (png_bytep) malloc(sizeof(png_byte) * png_height * 4);

        if (! color_at_pix) {
            fprintf(stderr, "Out of memory.\n");
            return 1;
        }

        int y;
        for (y = 0; y < png_height; ++y) {
            png_bytep row = (png_bytep) malloc(png_width * 4);
            if (! row) {
                fprintf(stderr, "Out of memory.\n");
                return 1;
            }
            row_pointers[y] = row;

            // compute the foreground color at each y pixel
            int i;
            for (i = 0; i < 4; ++i) {
                double amt = abs(y - png_center_y) / png_center_y_float;
                color_at_pix[4*y + i] = (1-amt) * color_center[i] + amt * color_outer[i];
            }
        }

        image_bound_y = png_height - 1;
    }

    FILE *waveformjs_f = NULL;
    int wjs_frames_per_pixel = 0;
    int16_t wjs_max_sample;
    int wjs_frames_until_emit = 0;
    int wjs_emit_count;
    if (waveformjs_output) {
        if (strcmp(waveformjs_output, "-") == 0) {
            waveformjs_f = stdout;
        } else {
            waveformjs_f = fopen(waveformjs_output, "wb");
            if (!waveformjs_f) {
                fprintf(stderr, "Error opening output file: %s\n", waveformjs_output);
                return 1;
            }
        }

        wjs_frames_per_pixel = frame_count / wjs_width;
        if (wjs_frames_per_pixel < 1)
            wjs_frames_per_pixel = 1;

        if (!wjs_plain) {
            fprintf(waveformjs_f, "{\"frameCount\":%d,\"frameRate\":%d, \"waveformjs\":",
                    frame_count, 44100);
        }

        fprintf(waveformjs_f, "[");

        wjs_max_sample = INT16_MIN;
        wjs_frames_until_emit = wjs_frames_per_pixel;
        wjs_emit_count = 0;
    }

    while (groove_sink_buffer_get(sink, &buffer, 1) == GROOVE_BUFFER_YES) {
        if (png_output) {
            int i;
            for (i = 0; i < buffer->frame_count && png_x < png_width;
                    i += 1, png_frames_until_emit -= 1)
            {
                if (png_frames_until_emit == 0) {
                    emit_png_column();
                }
                int16_t *samples = (int16_t *) buffer->data[0];
                int16_t left = samples[i];
                int16_t right = samples[i + 1];
                int16_t avg = (left + right) / 2;

                if (avg > png_max_sample) png_max_sample = avg;
                if (avg < png_min_sample) png_min_sample = avg;
            }
        }
        if (waveformjs_output) {
            int i;
            for (i = 0; i < buffer->frame_count && wjs_emit_count < wjs_width;
                    i += 1, wjs_frames_until_emit -= 1)
            {
                if (wjs_frames_until_emit == 0) {
                    wjs_emit_count += 1;
                    char *comma = (wjs_emit_count == wjs_width) ? "" : ",";
                    double float_sample = wjs_max_sample / (double) INT16_MAX;
                    fprintf(waveformjs_f, "%.*f%s", wjs_precision, float_sample, comma);
                    wjs_max_sample = INT16_MIN;
                    wjs_frames_until_emit = wjs_frames_per_pixel;
                }
                int16_t *data = (int16_t *) buffer->data[0];
                int16_t *left = &data[i];
                int16_t *right = &data[i + 1];
                int16_t abs_left = int16_abs(*left);
                int16_t abs_right = int16_abs(*right);
                if (abs_left > wjs_max_sample) wjs_max_sample = abs_left;
                if (abs_right > wjs_max_sample) wjs_max_sample = abs_right;
            }
        }

        groove_buffer_unref(buffer);
    }

    if (png_output) {
        // emit the last column if necessary. This will have to run multiple times
        // if the duration specified in the metadata is incorrect.
        while (png_x < png_width) {
            emit_png_column();
        }

        png_write_image(png, row_pointers);
        png_write_end(png, png_info);
        fclose(png_file);
    }

    if (waveformjs_output) {
        if (wjs_emit_count < wjs_width) {
            // emit the last sample
            double float_sample = wjs_max_sample / (double) INT16_MAX;
            fprintf(waveformjs_f, "%.*f", wjs_precision, float_sample);
        }

        fprintf(waveformjs_f, "]");

        if (!wjs_plain)
            fprintf(waveformjs_f, "}");

        fclose(waveformjs_f);
    }

    if (transcode_output) {
        pthread_join(thread_id, NULL);
        fclose(transcode_out_f);

        groove_encoder_detach(encoder);
        groove_encoder_destroy(encoder);
    }

    groove_sink_detach(sink);
    groove_sink_destroy(sink);

    groove_playlist_clear(playlist);
    groove_file_close(file);
    groove_playlist_destroy(playlist);

    return 0;
}


text:
package org.apache.dubbo.config;

import org.apache.dubbo.common.Constants;
import org.apache.dubbo.config.api.DemoService;
import org.apache.dubbo.config.provider.impl.DemoServiceImpl;

import org.junit.Assert;
import org.junit.Test;

public class ReferenceConfigTest {

    @Test
    public void testInjvm() throws Exception {
        ApplicationConfig application = new ApplicationConfig();
        application.setName("test-protocol-random-port");

        RegistryConfig registry = new RegistryConfig();
        registry.setAddress("multicast://224.5.6.7:1234");

        ProtocolConfig protocol = new ProtocolConfig();
        protocol.setName("dubbo");

        ServiceConfig<DemoService> demoService;
        demoService = new ServiceConfig<DemoService>();
        demoService.setInterface(DemoService.class);
        demoService.setRef(new DemoServiceImpl());
        demoService.setApplication(application);
        demoService.setRegistry(registry);
        demoService.setProtocol(protocol);

        ReferenceConfig<DemoService> rc = new ReferenceConfig<DemoService>();
        rc.setApplication(application);
        rc.setRegistry(registry);
        rc.setInterface(DemoService.class.getName());
        rc.setInjvm(false);

        try {
            demoService.export();
            rc.get();
            Assert.assertTrue(!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(
                    rc.getInvoker().getUrl().getProtocol()));
        } finally {
            demoService.unexport();
        }
    }
    /**
     * unit test for dubbo-1765
     */
    @Test
    public void testReferenceRetry() {
        ApplicationConfig application = new ApplicationConfig();
        application.setName("test-reference-retry");
        RegistryConfig registry = new RegistryConfig();
        registry.setAddress("multicast://224.5.6.7:1234");
        ProtocolConfig protocol = new ProtocolConfig();
        protocol.setName("dubbo");

        ReferenceConfig<DemoService> rc = new ReferenceConfig<DemoService>();
        rc.setApplication(application);
        rc.setRegistry(registry);
        rc.setInterface(DemoService.class.getName());

        boolean success = false;
        DemoService demoService = null;
        try {
            demoService = rc.get();
            success = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        Assert.assertFalse(success);
        Assert.assertNull(demoService);

        ServiceConfig<DemoService> sc = new ServiceConfig<DemoService>();
        sc.setInterface(DemoService.class);
        sc.setRef(new DemoServiceImpl());
        sc.setApplication(application);
        sc.setRegistry(registry);
        sc.setProtocol(protocol);

        try {
            sc.export();
            demoService = rc.get();
            success = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        Assert.assertTrue(success);
        Assert.assertNotNull(demoService);

    }
}


text:
module.exports = expectWithinNonInclusiveRange = function(input, isWithinNonInclusiveRange, debug) {

  // checks to ensure that input to test is a number
  if (typeof(input) !== 'number') {
    if (debug) {
      console.log('isWithinNonInclusiveRange can only test numbers; invalid input', input);
    }
    return false;
  }

  // checks to ensure that isWithinNonInclusiveRange is an array or two Numbers
  if (!Array.isArray(isWithinNonInclusiveRange) || isWithinNonInclusiveRange.length !== 2 || typeof(isWithinNonInclusiveRange[0]) !== 'number' || typeof(isWithinNonInclusiveRange[1]) !== 'number' || isWithinNonInclusiveRange[0] > isWithinNonInclusiveRange[1]) {
    if (debug) {
      console.log('invalid option', isWithinNonInclusiveRange, 'passed to isWithinNonInclusiveRange');
    }
    return false;
  }

  // checks if input is within the non-inclusive range
  if (input > isWithinNonInclusiveRange[0] && input < isWithinNonInclusiveRange[1]) {
    return true;
  } else {
    return false;
  }

};


text:
<?php

namespace KomtetTest\KassaSdk\v2;

use Komtet\KassaSdk\v2\MarkQuantity;
use PHPUnit\Framework\TestCase;

class MarkQuantityTest extends TestCase
{
    public function testMarkQuantitySuccess()
    {
        $mark_quantity = new MarkQuantity(3, 4);
        $this->assertEquals($mark_quantity->asArray(),
                            ['numerator' => 3,
                             'denominator' => 4]);
    }

    public function testMarkQuantitySuccess2()
    {
        $mark_quantity = new MarkQuantity(15, 1000);
        $this->assertEquals($mark_quantity->asArray(),
                            ['numerator' => 15,
                             'denominator' => 1000]);
    }

}


text:
<link rel="import" href="../card-inputs/inputs-repeater.html">
<link rel="import" href="../redaap-behaviors/utilities.html">
<link rel="import" href="../redaap-behaviors/on-tap-behavior.html">
<link rel="import" href="../redaap-behaviors/expand-collapse-classes-behavior.html">

<dom-module id="solution-card">
  <template>

    <paper-material id="expanding"
                    class="expanding"
                    elevation="2">
    </paper-material>

      <iron-icon class="itemIcons"
        icon="custom-icons:[[solution.icon]]"
        hidden$="[[!solution.icon]]">
      </iron-icon>

[[solution.label]]

	      <paper-input class="customInput"
	                   type="tel"
	                   label="Product"
	                   maxLength="6"
	                   min="0"
	                   allowed-pattern="[0-9]"
	                   prevent-invalid-input
	                   value="{{solution.customProduct}}"
                     disabled="[[disabled]]">

$

	      </paper-input>
	      <paper-input id="centerCustomInput"
	                   class="customInput"
	                   type="tel"
	                   label="Install"
	                   maxLength="6"
	                   min="0"
	                   allowed-pattern="[0-9]"
	                   prevent-invalid-input
	                   value="{{solution.customInstall}}"
                     disabled="[[disabled]]">

$

	      </paper-input>
	      <paper-input class="customInput"
	                   type="tel"
	                   label="Quantity"
	                   maxLength="6"
	                   min="0"
	                   allowed-pattern="[0-9]"
	                   prevent-invalid-input
	                   value="{{solution.count}}"
                     disabled="[[disabled]]">
	      </paper-input>

	    <inputs-repeater class="inputs"
	                     array="[[solution.tallies]]"
	                     hidden$="[[solution.custom]]"
                       disabled="[[disabled]]">
	    </inputs-repeater>

	      <paper-icon-button
	        class="buttons"
	        hidden$="[[solution.custom]]"
	        on-tap="_addTallyButtonTapped"
	        icon="custom-icons:add"
          disabled="[[disabled]]">
	      </paper-icon-button>
	      <paper-button class="buttons"
                      on-tap="_saveButtonTapped"
                      disabled="[[disabled]]">
                      save
        </paper-button>

[[solution.count]]

  </template>

</dom-module>


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace LegacyEnterpriseWebApp.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Title = "Home Page";

            return View();
        }

        public ActionResult New()
        {
            ViewBag.Title = "New Stuff";

            return View();
        }
    }
}


text:
package org.aesh.command.validator;

/**
 * @author Ståle W. Pedersen
 */
public class CommandValidatorException extends Exception {

    public CommandValidatorException(String s) {
        super(s);
    }
}


text:
'use babel';

import NcGcode from '../lib/nc-gcode';

// Use the command `window:run-package-specs` (cmd-alt-ctrl-p) to run specs.
//
// To run a specific `it` or `describe` block add an `f` to the front (e.g. `fit`
// or `fdescribe`). Remove the `f` to unfocus the block.

describe('NcGcode', () => {
  let workspaceElement, activationPromise;

  beforeEach(() => {
    workspaceElement = atom.views.getView(atom.workspace);
    activationPromise = atom.packages.activatePackage('nc-gcode');
  });

  describe('when the nc-gcode:toggle event is triggered', () => {
    it('hides and shows the modal panel', () => {
      // Before the activation event the view is not on the DOM, and no panel
      // has been created
      expect(workspaceElement.querySelector('.nc-gcode')).not.toExist();

      // This is an activation event, triggering it will cause the package to be
      // activated.
      atom.commands.dispatch(workspaceElement, 'nc-gcode:toggle');

      waitsForPromise(() => {
        return activationPromise;
      });

      runs(() => {
        expect(workspaceElement.querySelector('.nc-gcode')).toExist();

        let ncGcodeElement = workspaceElement.querySelector('.nc-gcode');
        expect(ncGcodeElement).toExist();

        let ncGcodePanel = atom.workspace.panelForItem(ncGcodeElement);
        expect(ncGcodePanel.isVisible()).toBe(true);
        atom.commands.dispatch(workspaceElement, 'nc-gcode:toggle');
        expect(ncGcodePanel.isVisible()).toBe(false);
      });
    });

    it('hides and shows the view', () => {
      // This test shows you an integration test testing at the view level.

      // Attaching the workspaceElement to the DOM is required to allow the
      // `toBeVisible()` matchers to work. Anything testing visibility or focus
      // requires that the workspaceElement is on the DOM. Tests that attach the
      // workspaceElement to the DOM are generally slower than those off DOM.
      jasmine.attachToDOM(workspaceElement);

      expect(workspaceElement.querySelector('.nc-gcode')).not.toExist();

      // This is an activation event, triggering it causes the package to be
      // activated.
      atom.commands.dispatch(workspaceElement, 'nc-gcode:toggle');

      waitsForPromise(() => {
        return activationPromise;
      });

      runs(() => {
        // Now we can test for view visibility
        let ncGcodeElement = workspaceElement.querySelector('.nc-gcode');
        expect(ncGcodeElement).toBeVisible();
        atom.commands.dispatch(workspaceElement, 'nc-gcode:toggle');
        expect(ncGcodeElement).not.toBeVisible();
      });
    });
  });
});


text:
extern zend_class_entry *zendframework_stdlib_exception_logicexception_ce;

ZEPHIR_INIT_CLASS(ZendFramework_Stdlib_Exception_LogicException);


text:
import pytest
from helpers import for_one_database, get_credentials

from turbodbc import connect

"""
Test optional features mentioned in PEP-249 "behave" as specified
"""

@for_one_database
def test_callproc_unsupported(dsn, configuration):
    cursor = connect(dsn, **get_credentials(configuration)).cursor()

    with pytest.raises(AttributeError):
        cursor.callproc()

@for_one_database
def test_nextset_unsupported(dsn, configuration):
    cursor = connect(dsn, **get_credentials(configuration)).cursor()

    with pytest.raises(AttributeError):
        cursor.nextset()