text:
<?php

if ( !defined( 'ABSPATH' ) ) {
	die();
}

define( 'W3TC', true );
define( 'W3TC_VERSION', '2.1.2' );
define( 'W3TC_POWERED_BY', 'W3 Total Cache' );
define( 'W3TC_EMAIL', 'w3tc@w3-edge.com' );
define( 'W3TC_TEXT_DOMAIN', 'w3-total-cache' );
define( 'W3TC_LINK_URL', 'https://api.w3-edge.com/v1/redirects/product-index' );
define( 'W3TC_LINK_NAME', 'W3 EDGE, Optimization Products for WordPress' );
define( 'W3TC_FEED_URL', 'https://api.w3-edge.com/v1/redirects/product-rss' );
define( 'W3TC_NEWS_FEED_URL', 'https://api.w3-edge.com/v1/redirects/company-rss' );
define( 'W3TC_README_URL', 'https://api.w3-edge.com/v1/redirects/product-readme' );
define( 'W3TC_SUPPORT_US_PRODUCT_URL', 'https://api.w3-edge.com/v1/redirects/product-directory' );
define( 'W3TC_SUPPORT_US_RATE_URL', 'https://api.w3-edge.com/v1/redirects/support-ratings' );
define( 'W3TC_SUPPORT_US_TWEET', 'YES! I optimized the user experience of my website with the W3 Total Cache #WordPress #plugin by @w3edge! http://bit.ly/TeSBL3' );
define( 'W3TC_EDGE_TIMEOUT', 7 * 24 * 60 * 60 );
define( 'W3TC_SUPPORT_REQUEST_URL', 'https://api.w3-edge.com/v1/support-request' );
define( 'W3TC_SUPPORT_SERVICES_URL', 'https://api.w3-edge.com/v1/support-serviceinventory' );
define( 'W3TC_FAQ_URL', 'https://api.w3-edge.com/v1/redirects/faq' );
define( 'W3TC_TERMS_URL', 'https://api.w3-edge.com/v1/redirects/policies-terms' );
define( 'W3TC_TERMS_ACCEPT_URL', 'https://api.w3-edge.com/v1/redirects/policies-accept' );
define( 'W3TC_MAILLINGLIST_SIGNUP_URL', 'https://api.w3-edge.com/v1/signup-newsletter' );
define( 'W3TC_NEWRELIC_SIGNUP_URL', 'https://api.w3-edge.com/v1/redirects/newrelic/signup' );
define( 'W3TC_MAXCDN_SIGNUP_URL', 'https://api.w3-edge.com/v1/redirects/maxcdn/signup' );
define( 'W3TC_MAXCDN_AUTHORIZE_URL', 'https://api.w3-edge.com/v1/redirects/maxcdn/authorize' );
define( 'W3TC_STACKPATH_SIGNUP_URL', 'https://api.w3-edge.com/v1/redirects/stackpath/signup' );
define( 'W3TC_STACKPATH_AUTHORIZE_URL', 'https://api.w3-edge.com/v1/redirects/stackpath/authorize' );
define( 'W3TC_STACKPATH2_AUTHORIZE_URL', 'https://api.w3-edge.com/v1/redirects/stackpath2/authorize' );
define( 'W3TC_GOOGLE_DRIVE_AUTHORIZE_URL', 'https://api.w3-edge.com/v1/googledrive/authorize' );

// this is the URL our updater / license checker pings. This should be the URL of the site with EDD installed
if ( !defined( 'W3TC_LICENSE_API_URL' ) ) {
	define( 'W3TC_LICENSE_API_URL', 'https://www.w3-edge.com/' );
}
if ( !defined( 'W3TC_PURCHASE_URL' ) ) {
	define( 'W3TC_PURCHASE_URL', 'https://www.w3-edge.com/checkout/' );
}

// the name of your product. This should match the download name in EDD exactly
define( 'W3TC_PURCHASE_PRODUCT_NAME', 'W3 Total Cache Pro: Annual Subscription' );

define( 'W3TC_WIN', ( strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN' ) );

if ( !defined( 'W3TC_DIR' ) )
	define( 'W3TC_DIR', realpath( dirname( __FILE__ ) ) );

define( 'W3TC_FILE', 'w3-total-cache/w3-total-cache.php' );
define( 'W3TC_INC_DIR', W3TC_DIR . '/inc' );
define( 'W3TC_INC_WIDGET_DIR', W3TC_INC_DIR. '/widget' );
define( 'W3TC_INC_OPTIONS_DIR', W3TC_INC_DIR . '/options' );
define( 'W3TC_INC_LIGHTBOX_DIR', W3TC_INC_DIR . '/lightbox' );
define( 'W3TC_INC_POPUP_DIR', W3TC_INC_DIR . '/popup' );
define( 'W3TC_LIB_DIR', W3TC_DIR . '/lib' );
define( 'W3TC_LIB_NETDNA_DIR', W3TC_LIB_DIR . '/NetDNA' );
define( 'W3TC_LIB_NEWRELIC_DIR', W3TC_LIB_DIR . '/NewRelic' );
define( 'W3TC_INSTALL_DIR', W3TC_DIR . '/wp-content' );
define( 'W3TC_INSTALL_MINIFY_DIR', W3TC_INSTALL_DIR . '/w3tc/min' );
define( 'W3TC_LANGUAGES_DIR', W3TC_DIR . '/languages' );

if ( !defined( 'WP_CONTENT_DIR' ) )
	define( 'WP_CONTENT_DIR', realpath( W3TC_DIR . '/../..' ) );

if ( !defined( 'W3TC_CACHE_DIR' ) )
	define( 'W3TC_CACHE_DIR', WP_CONTENT_DIR . '/cache' );
if ( !defined( 'W3TC_CONFIG_DIR' ) )
	define( 'W3TC_CONFIG_DIR', WP_CONTENT_DIR . '/w3tc-config' );
if ( !defined( 'W3TC_CACHE_MINIFY_DIR' ) )
	define( 'W3TC_CACHE_MINIFY_DIR', W3TC_CACHE_DIR  . '/minify' );
if ( !defined( 'W3TC_CACHE_PAGE_ENHANCED_DIR' ) )
	define( 'W3TC_CACHE_PAGE_ENHANCED_DIR', W3TC_CACHE_DIR  . '/page_enhanced' );
if ( !defined( 'W3TC_CACHE_TMP_DIR' ) )
	define( 'W3TC_CACHE_TMP_DIR', W3TC_CACHE_DIR . '/tmp' );
if ( !defined( 'W3TC_CACHE_BLOGMAP_FILENAME' ) )
	define( 'W3TC_CACHE_BLOGMAP_FILENAME', W3TC_CACHE_DIR . '/blogs.php' );
if ( !defined( 'W3TC_CACHE_FILE_EXPIRE_MAX' ) )
	define( 'W3TC_CACHE_FILE_EXPIRE_MAX', 2592000 );

define( 'W3TC_CDN_COMMAND_UPLOAD', 1 );
define( 'W3TC_CDN_COMMAND_DELETE', 2 );
define( 'W3TC_CDN_COMMAND_PURGE', 3 );
define( 'W3TC_CDN_TABLE_QUEUE', 'w3tc_cdn_queue' );
define( 'W3TC_CDN_TABLE_PATHMAP', 'w3tc_cdn_pathmap' );

define( 'W3TC_INSTALL_FILE_ADVANCED_CACHE', W3TC_INSTALL_DIR . '/advanced-cache.php' );
define( 'W3TC_INSTALL_FILE_DB', W3TC_INSTALL_DIR . '/db.php' );
define( 'W3TC_INSTALL_FILE_OBJECT_CACHE', W3TC_INSTALL_DIR . '/object-cache.php' );

define( 'W3TC_ADDIN_FILE_ADVANCED_CACHE', WP_CONTENT_DIR . '/advanced-cache.php' );
define( 'W3TC_ADDIN_FILE_DB', WP_CONTENT_DIR . '/db.php' );
define( 'W3TC_FILE_DB_CLUSTER_CONFIG', WP_CONTENT_DIR . '/db-cluster-config.php' );
define( 'W3TC_ADDIN_FILE_OBJECT_CACHE', WP_CONTENT_DIR . '/object-cache.php' );

define( 'W3TC_MARKER_BEGIN_WORDPRESS', '# BEGIN WordPress' );
define( 'W3TC_MARKER_BEGIN_PGCACHE_CORE', '# BEGIN W3TC Page Cache core' );
define( 'W3TC_MARKER_BEGIN_PGCACHE_CACHE', '# BEGIN W3TC Page Cache cache' );
define( 'W3TC_MARKER_BEGIN_PGCACHE_WPSC', '# BEGIN WPSuperCache' );
define( 'W3TC_MARKER_BEGIN_BROWSERCACHE_CACHE', '# BEGIN W3TC Browser Cache' );
define( 'W3TC_MARKER_BEGIN_BROWSERCACHE_NO404WP', '# BEGIN W3TC Skip 404 error handling by WordPress for static files' );
define( 'W3TC_MARKER_BEGIN_MINIFY_CORE', '# BEGIN W3TC Minify core' );
define( 'W3TC_MARKER_BEGIN_MINIFY_CACHE', '# BEGIN W3TC Minify cache' );
define( 'W3TC_MARKER_BEGIN_MINIFY_LEGACY', '# BEGIN W3TC Minify' );
define( 'W3TC_MARKER_BEGIN_CDN', '# BEGIN W3TC CDN' );

define( 'W3TC_MARKER_END_WORDPRESS', '# END WordPress' );
define( 'W3TC_MARKER_END_PGCACHE_CORE', '# END W3TC Page Cache core' );
define( 'W3TC_MARKER_END_PGCACHE_CACHE', '# END W3TC Page Cache cache' );
define( 'W3TC_MARKER_END_PGCACHE_LEGACY', '# END W3TC Page Cache' );
define( 'W3TC_MARKER_END_PGCACHE_WPSC', '# END WPSuperCache' );
define( 'W3TC_MARKER_END_BROWSERCACHE_CACHE', '# END W3TC Browser Cache' );
define( 'W3TC_MARKER_END_BROWSERCACHE_NO404WP', '# END W3TC Skip 404 error handling by WordPress for static files' );
define( 'W3TC_MARKER_END_MINIFY_CORE', '# END W3TC Minify core' );
define( 'W3TC_MARKER_END_MINIFY_CACHE', '# END W3TC Minify cache' );
define( 'W3TC_MARKER_END_MINIFY_LEGACY', '# END W3TC Minify' );
define( 'W3TC_MARKER_END_CDN', '# END W3TC CDN' );
define( 'W3TC_MARKER_END_NEW_RELIC_CORE', '# END W3TC New Relic core' );

if ( !defined( 'W3TC_EXTENSION_DIR' ) ) {
	define( 'W3TC_EXTENSION_DIR', ( defined( 'WP_PLUGIN_DIR' ) ? WP_PLUGIN_DIR : WP_CONTENT_DIR . '/plugins' ) );
}

if ( !defined( 'W3TC_WP_JSON_URI' ) ) {
	define( 'W3TC_WP_JSON_URI', '/wp-json/' );
}
if ( !defined( 'W3TC_FEED_REGEXP' ) ) {
	define( 'W3TC_FEED_REGEXP', '~/feed(/|$)~' );
}

@ini_set( 'pcre.backtrack_limit', 4194304 );
@ini_set( 'pcre.recursion_limit', 4194304 );

global $w3_late_init;
$w3_late_init = false;

/**
 * Class autoloader
 *
 * @param string  $class Classname
 */
function w3tc_class_autoload( $class ) {
	// some php pass classes with slash
	if ( substr( $class, 0, 1 ) == "\\" ) {
		$class = substr( $class, 1 );
	}

	// try core w3tc classes first
	if ( substr( $class, 0, 5 ) == 'W3TC\\' ) {
		$filename = W3TC_DIR . DIRECTORY_SEPARATOR . substr( $class, 5 ) . '.php';

		if ( file_exists( $filename ) ) {
			require $filename;
			return;
		} else {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
				echo 'Attempt to create object of class ' .
					$class . ' has been made, but file ' .
					$filename . ' doesnt exists';
				debug_print_backtrace();
			}
		}
	}

	if ( substr( $class, 0, 13 ) == 'W3TCG_Google_' &&
		( !defined( 'W3TC_GOOGLE_LIBRARY' ) || W3TC_GOOGLE_LIBRARY ) ) {
		// Google library
		$classPath = explode( '_', substr( $class, 6 ) );
		if ( count( $classPath ) > 3 ) {
			// Maximum class file path depth in this project is 3.
			$classPath = array_slice( $classPath, 0, 3 );
		}

		$filePath = W3TC_LIB_DIR . DIRECTORY_SEPARATOR .
			implode( '/', $classPath ) . '.php';

		if ( file_exists( $filePath ) )
			require $filePath;
		return;
	}

	if ( substr( $class, 0, 6 ) == 'W3TCL\\' ) {
		$base = W3TC_LIB_DIR . DIRECTORY_SEPARATOR;
		$class = substr( $class, 6 );

		// psr loader
		$file = $base . strtr( $class, "\\_",
			DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR ) . '.php';
		if ( file_exists( $file ) )
			require_once $file;
	}
}

spl_autoload_register( 'w3tc_class_autoload' );

/**
 * W3 Total Cache plugins API
 */

/**
 * Returns config.
 *
 * !!! NOTICE !!!
 * 3rd party developers, please do not modify the plugin's configuration without
 * notifying the user beforehand. As an alternative, throw a notification to the
 * user like: "Configure W3 Total Cache for me" and allow the user to dismiss
 * the notification.
 * !!! NOTICE !!!
 */
function w3tc_config() {
	/*
	 * Some plugins make incorrect decisions based on configuration
	 * and force to disable modules working otherwise or
	 * adds notices on each wp-admin page without ability to remove it.
	 * By defining W3TC_CONFIG_HIDE you may still use w3tc configuration you like.
	 */
	if ( defined( 'W3TC_CONFIG_HIDE' ) && W3TC_CONFIG_HIDE )
		return new W3_Config();

	$config = \W3TC\Dispatcher::config();
	return $config;
}

/**
 * Purges/Flushes everything
 */
function w3tc_flush_all( $extras = null ) {
	$o = \W3TC\Dispatcher::component( 'CacheFlush' );
	$o->flush_all( $extras );
}

/**
 * Purges/Flushes post page
 */
function w3tc_flush_post( $post_id, $extras = null ) {
	$o = \W3TC\Dispatcher::component( 'CacheFlush' );
	$o->flush_post( $post_id, $extras );
}

/**
 * Purges/Flushes all posts
 */
function w3tc_flush_posts( $extras = null ) {
	$o = \W3TC\Dispatcher::component( 'CacheFlush' );
	$o->flush_posts( $extras );
}

/**
 * Purges/Flushes url
 */
function w3tc_flush_url( $url, $extras = null ) {
	$o = \W3TC\Dispatcher::component( 'CacheFlush' );
	$o->flush_url( $url, $extras );
}

/**
 * Purges/Flushes separate cache group
 */
function w3tc_flush_group( $group, $extras = null ) {
	$o = \W3TC\Dispatcher::component( 'CacheFlush' );
	$o->flush_group( $group, $extras );
}

/**
 * deprecated
 * Shortcut for page cache flush
 *
 * @return boolean
 */
function w3tc_pgcache_flush() {
	return w3tc_flush_posts();
}

/**
 * deprecated
 * Shortcut for page post cache flush
 *
 * @param integer $post_id
 * @return boolean
 */
function w3tc_pgcache_flush_post( $post_id ) {
	return w3tc_flush_post( $post_id );
}

/**
 * deprecated
 * Shortcut for page post cache flush by url
 *
 * @param integer $url
 * @return boolean
 */
function w3tc_pgcache_flush_url( $url ) {
	return w3tc_flush_url( $url );
}

/**
 * deprecated
 * Shortcut for refreshing the media query string.
 */
function w3tc_browsercache_flush() {
	$o = \W3TC\Dispatcher::component( 'CacheFlush' );
	return $o->browsercache_flush();
}

/**
 * deprecated
 * Shortcut for database cache flush
 *
 */
function w3tc_dbcache_flush() {
	$o = \W3TC\Dispatcher::component( 'CacheFlush' );
	$o->dbcache_flush();
}

/**
 * deprecated
 * Shortcut for minify cache flush
 *
 */
function w3tc_minify_flush() {
	$o = \W3TC\Dispatcher::component( 'CacheFlush' );
	$o->minifycache_flush();

}

/**
 * deprecated
 * Shortcut for objectcache cache flush
 *
 */
function w3tc_objectcache_flush() {
	$o = \W3TC\Dispatcher::component( 'CacheFlush' );
	$o->objectcache_flush();
}

/**
 * deprecated
 * Shortcut for CDN purge files
 *
 * @param array   $files Array consisting of uri paths (i.e wp-content/uploads/image.pnp)
 * @return mixed
 */
function w3tc_cdn_purge_files( $files ) {
	$o = \W3TC\Dispatcher::component( 'CacheFlush' );
	return $o->cdn_purge_files( $files );
}

/**
 * deprecated
 * Prints script tag for scripts group
 *
 * @param string  $location
 * @retun void
 */
function w3tc_minify_script_group( $location ) {
	$o = \W3TC\Dispatcher::component( 'Minify_Plugin' );
	$o->printed_scripts[] = $location;

	$r = $o->get_script_group( $location );
	echo $r['body'];
}

/**
 * deprecated
 * Prints style tag for styles group
 *
 * @param string  $location
 * @retun void
 */
function w3tc_minify_style_group( $location ) {
	$o = \W3TC\Dispatcher::component( 'Minify_Plugin' );
	$o->printed_styles[] = $location;

	$r = $o->get_style_group( $location );
	echo $r['body'];
}

/**
 * deprecated
 * Prints script tag for custom scripts
 *
 * @param string|array $files
 * @param boolean $blocking
 * @return void
 */
function w3tc_minify_script_custom( $files, $blocking = true ) {
	$o = \W3TC\Dispatcher::component( 'Minify_Plugin' );
	echo $o->get_script_custom( $files, $blocking );
}

/**
 * deprecated
 * Prints style tag for custom styles
 *
 * @param string|array $files
 * @return void
 */
function w3tc_minify_style_custom( $files ) {
	$o = \W3TC\Dispatcher::component( 'Minify_Plugin' );
	$r = $o->get_style_custom( $files );
	echo $r['body'];
}

/**
 * deprecated
 * Use Util_Theme::get_themes() to get a list themenames to use with user agent groups
 *
 * @param unknown $group_name
 * @param string  $theme      the themename default is default theme. For childtheme it should be parentthemename/childthemename
 * @param string  $redirect
 * @param array   $agents     Remember to escape special characters like spaces, dots or dashes with a backslash. Regular expressions are also supported.
 * @param bool    $enabled
 */
function w3tc_save_user_agent_group( $group_name, $theme = 'default', $redirect = '', $agents = array(), $enabled = false ) {
	$o = \W3TC\Dispatcher::component( 'Mobile_UserAgent' );
	$o->save_group( $group_name, $theme, $redirect, $agents, $enabled );
}

/**
 * deprecated
 *
 * @param unknown $group
 */
function w3tc_delete_user_agent_group( $group ) {
	$o = \W3TC\Dispatcher::component( 'Mobile_UserAgent' );
	$o->delete_group( $group );

}

/**
 * deprecated
 *
 * @param unknown $group
 * @return mixed
 */
function w3tc_get_user_agent_group( $group ) {
	$o = \W3TC\Dispatcher::component( 'Mobile_UserAgent' );
	return $o->get_group_values( $group );
}

/**
 * deprecated
 * Use Util_Theme::get_themes() to get a list themenames to use with referrer groups
 *
 * @param unknown $group_name
 * @param string  $theme      the themename default is default theme. For childtheme it should be parentthemename/childthemename
 * @param string  $redirect
 * @param array   $referrers  Remember to escape special characters like spaces, dots or dashes with a backslash. Regular expressions are also supported.
 * @param bool    $enabled
 */
function w3tc_save_referrer_group( $group_name, $theme = 'default', $redirect = '', $referrers = array(), $enabled = false ) {
	$o = \W3TC\Dispatcher::component( 'Mobile_Referrer' );
	$o->save_group( $group_name, $theme, $redirect, $referrers, $enabled );
}

/**
 * deprecated
 *
 * @param unknown $group
 */
function w3tc_delete_referrer_group( $group ) {
	$o = \W3TC\Dispatcher::component( 'Mobile_Referrer' );
	$o->delete_group( $group );
}

/**
 * deprecated
 *
 * @param unknown $group
 * @return mixed
 */
function w3tc_get_referrer_group( $group ) {
	$o = \W3TC\Dispatcher::component( 'Mobile_Referrer' );
	return $o->get_group_values( $group );
}

/**
 * deprecated
 * Flushes files from opcache.
 *
 * @param bool    $http if delete request should be made over http to current site. Default false.
 * @return mixed
 */
function w3tc_opcache_flush( $http = false ) {
	if ( !$http ) {
		$o = \W3TC\Dispatcher::component( 'CacheFlush' );
		return $o->opcache_flush();
	} else {
		$url = WP_PLUGIN_URL . '/' . dirname( W3TC_FILE ) . '/pub/opcache.php';
		$path = parse_url( $url, PHP_URL_PATH );
		$post = array(
			'method' => 'POST',
			'timeout' => 45,
			'redirection' => 5,
			'httpversion' => '1.0',
			'blocking' => true,
			'body' => array(
				'nonce' => wp_hash( $path ),
				'command' => 'flush' ),
		);
		$result = wp_remote_post( $url, $post );
		if ( is_wp_error( $result ) ) {
			return $result;
		} elseif ( $result['response']['code'] != '200' ) {
			return $result['response']['code'];
		}

		return true;
	}
}

/**
 * Deprecated. Retained for 3rd parties that used it. see w3tc_config()
 *
 * Some plugins make incorrect decisions based on configuration
 * and force to disable modules working otherwise or
 * adds notices on each wp-admin page without ability to remove it.
 * By defining W3TC_CONFIG_HIDE you may still use w3tc configuration you like.
 */
if ( defined( 'W3TC_CONFIG_HIDE' ) && W3TC_CONFIG_HIDE ) {
	class W3_Config {
		public function __construct( $master = false, $blog_id = null ) {
		}

		public function get_string( $key, $default = '', $trim = true ) {
			return '';
		}

		public function get_integer( $key, $default = 0 ) {
			return 0;
		}

		public function get_boolean( $key, $default = false ) {
			return false;
		}
	}
} else {
	class W3_Config extends \W3TC\Config {
		public function __construct( $master = false, $blog_id = null ) {
			if ( $master )
				$blog_id = 0;

			return parent::__construct($blog_id);
		}
	}
}

/**
 * Deprecated. Retained for 3rd parties that use it. see w3tc_config()
 */
class W3_ConfigWriter {
	public function __construct( $p1 = 0, $p2 = 0 ) {
	}
	public function set( $p1 = 0, $p2 = 0 ) {
	}
	public function save( $p1 = 0, $p2 = 0 ) {
	}
	public function refresh_w3tc() {
	}
}

/**
Deprecated. Retained for 3rd parties that use it. see w3tc_config()
*/
function w3_instance( $class ) {
	$legacy_class_name = null;

	if ( $class == 'W3_Config' ) {
		if ( defined( 'W3TC_CONFIG_HIDE' ) && W3TC_CONFIG_HIDE )
			return new W3_Config();

		   $legacy_class_name = 'Config';
	}
	elseif ( $class == 'W3_ObjectCacheBridge' )
		$legacy_class_name = 'ObjectCache_WpObjectCache';
	elseif ( $class == 'W3_PgCache' )
		$legacy_class_name = 'PgCache_ContentGrabber';
	elseif ( $class == 'W3_Redirect' )
		$legacy_class_name = 'Mobile_Redirect';
	else
		return null;

	return \W3TC\Dispatcher::component( $legacy_class_name );
}

function w3tc_e( $key, $default_value ) {
	echo w3tc_er( $key, $default_value);
}

function w3tc_er( $key, $default_value ) {
	$default_value = __( $default_value , 'w3-total-cache' );
	$v = get_site_option( 'w3tc_generic_widgetservices' );
	try {
		$v = json_decode( $v, true );
		if ( !isset( $v['content'] ) ) {
			return $default_value;
		}

		$v = $v['content'];
	} catch ( \Exception $e ) {
		return $default_value;
	}

	global $w3tc_locale;
	if ( null === $w3tc_locale ) {
		if ( function_exists( 'get_user_locale' ) ) {
			$w3tc_locale = get_user_locale();
		} else {
			$w3tc_locale = '';
		}
	}

	if ( isset( $v["ui_strings.$w3tc_locale"][$key] ) ) {
		return $v["ui_strings.$w3tc_locale"][$key];
	}
	if ( isset( $v["ui_strings"][$key] ) ) {
		return $v["ui_strings"][$key];
	}

	return $default_value;
}

$w3tc_actions = array();

/**
 * add_action alternative used by W3TC when WP core is not available
 */
function w3tc_add_action( $hook, $callback ) {
	global $w3tc_actions;
	if ( !isset( $w3tc_actions[$hook] ) ) {
		$w3tc_actions[$hook] = array();
	}

	$w3tc_actions[$hook][] = $callback;
}

/**
 * do_action alternative used by W3TC when WP core is not available
 */
function w3tc_do_action( $hook ) {
	global $w3tc_actions;
	if (!empty($w3tc_actions[$hook])) {
		foreach ( $w3tc_actions[$hook] as $callback ) {
			call_user_func_array( $callback, array() );
		}
	}
}

/**
 * do_action alternative used by W3TC when WP core is not available
 */
function w3tc_apply_filters( $hook, $value ) {
	$args = func_get_args();
	array_shift( $args );

	global $w3tc_actions;
	if (!empty($w3tc_actions[$hook])) {
		foreach ( $w3tc_actions[$hook] as $callback ) {
			$value = call_user_func_array( $callback, $args );
			$args[0] = $value;
		}
	}

	return $value;
}


text:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;

using Pixiv.Attributes;
using Pixiv.Clients.V1.Novel;
using Pixiv.Enums;
using Pixiv.Extensions;
using Pixiv.Models;

namespace Pixiv.Clients.V1
{
    public class NovelClient : ApiClient
    {
        public BookmarkClient Bookmark { get; }

        internal NovelClient(PixivClient client) : base(client, "/v1/novel")
        {
            Bookmark = new BookmarkClient(client);
        }

        [ApiVersion]
        [MarkedAs("7.7.7")]
        [RequiredAuthentication]
        public async Task<NovelCollection> FollowAsync(Restrict restrict, long? offset = null)
        {
            var parameters = new List<KeyValuePair<string, object>>
            {
                new KeyValuePair<string, object>(nameof(restrict), restrict.ToValue())
            };
            if (offset.HasValue)
                parameters.Add(new KeyValuePair<string, object>(nameof(offset), offset.Value));

            return await GetAsync<NovelCollection>("/follow", parameters).Stay();
        }

        [ApiVersion]
        [MarkedAs("7.7.7")]
        [RequiredAuthentication]
        public async Task<NovelCollection> MypixivAsync(long? offset = null)
        {
            var parameters = new List<KeyValuePair<string, object>>();
            if (offset.HasValue)
                parameters.Add(new KeyValuePair<string, object>(nameof(offset), offset.Value));

            return await GetAsync<NovelCollection>("/mypixiv", parameters).Stay();
        }

        [ApiVersion]
        [MarkedAs("7.7.7")]
        [RequiredAuthentication]
        public async Task<NovelCollection> NewAsync(long? maxNovelId = null)
        {
            var parameters = new List<KeyValuePair<string, object>>();
            if (maxNovelId.HasValue)
                parameters.Add(new KeyValuePair<string, object>("max_novel_id", maxNovelId.Value));

            return await GetAsync<NovelCollection>("/new", parameters).Stay();
        }

        [ApiVersion]
        [MarkedAs("7.7.7")]
        [RequiredAuthentication]
        public async Task<NovelCollection> RankingAsync(RankingMode mode, DateTime? date = null, long? offset = null)
        {
            var parameters = new List<KeyValuePair<string, object>>
            {
                new KeyValuePair<string, object>(nameof(mode), mode.ToValue())
            };
            if (date.HasValue)
                parameters.Add(new KeyValuePair<string, object>(nameof(date), date.Value.ToString("YYYY-MM-dd", CultureInfo.InvariantCulture)));
            if (offset.HasValue)
                parameters.Add(new KeyValuePair<string, object>(nameof(offset), offset.Value));

            return await GetAsync<NovelCollection>("/ranking", parameters).Stay();
        }

        [ApiVersion]
        [MarkedAs("7.7.7")]
        [RequiredAuthentication]
        public async Task<NovelCollection> RecommendedAsync(bool includeRankingNovels = true, bool includePrivacyPolicy = true, long? maxBookmarkIdForRecommend = null, long? offset = null)
        {
            var parameters = new List<KeyValuePair<string, object>>
            {
                new KeyValuePair<string, object>("include_ranking_novels", includeRankingNovels),
                new KeyValuePair<string, object>("include_privacy_policy", includePrivacyPolicy)
            };
            if (maxBookmarkIdForRecommend.HasValue)
                parameters.Add(new KeyValuePair<string, object>("max_bookmark_id_for_recommend", maxBookmarkIdForRecommend.Value));
            if (offset.HasValue)
                parameters.Add(new KeyValuePair<string, object>(nameof(offset), offset.Value));

            return await GetAsync<NovelCollection>("/recommended", parameters).Stay();
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
package com.salama.service.clouddata.config;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author XingGu Liu
 *
 */
public class CloudDataServiceContext implements Serializable {
	/**
	 *
	 */
	private static final long serialVersionUID = 2563907768059493811L;

	private String authTicketManagerBackupDirPath = "";

	private List<CloudDataAppConfig> appConfigs = new ArrayList<CloudDataAppConfig>();

	public List<CloudDataAppConfig> getAppConfigs() {
		return appConfigs;
	}

	public void setAppConfigs(List<CloudDataAppConfig> appConfigs) {
		this.appConfigs = appConfigs;
	}

	public String getAuthTicketManagerBackupDirPath() {
		return authTicketManagerBackupDirPath;
	}

	public void setAuthTicketManagerBackupDirPath(
			String authTicketManagerBackupDirPath) {
		this.authTicketManagerBackupDirPath = authTicketManagerBackupDirPath;
	}

}


text:
///////////////////////////////////////////////////////////////////////////////
//                   SOFTWARE COPYRIGHT NOTICE AGREEMENT                     //
//       This software and its documentation are copyright (2015) by the     //
//   Broad Institute.  All rights are reserved.  This software is supplied   //
//   without any warranty or guaranteed support whatsoever. The Broad        //
//   Institute is not responsible for its use, misuse, or functionality.     //
///////////////////////////////////////////////////////////////////////////////
/*
 * ReadBAM.cc
 *
 *  Created on: Aug 29, 2014
 *      Author: tsharpe
 */

#include "bam/ReadBAM.h"
#include "IteratorRange.h"
#include "ParallelVecUtilities.h"
#include "system/LockedData.h"
#include "system/SortInPlace.h"
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
#include <istream>
#include <thread>
// MakeDepend: library ZLIB
#include <zlib.h>
#include <iostream>

#include "Vec.h"

namespace
{

// image of a block header for a BGZF-compressed file
struct GZipHeader
{

    size_t getBlockLen() const { return mBlockSizeLessOne+1ul; }

    bool isBGZFBlock() const
    { return mID==BGZF_ID && mCompressionMethod==BGZF_CM &&
            mFlags&BGZF_FXTRA && mXLen==BGZF_XLEN &&
            mSI==BGZF_SI && mSLen==BGZF_SLEN; }

    bool hasFName() const { return mFlags&BGZF_FNAME; }
    bool hasComment() const { return mFlags&BGZF_FCMNT; }
    bool hasHdrCRC() const { return mFlags&BGZF_FHCRC; }

    uint16_t mID;
    uint8_t mCompressionMethod;
    uint8_t mFlags;
    uint8_t mModTime[4]; // actually uint32_t, but we don't want any padding
    uint8_t mExtraFlags;
    uint8_t mOpSys;
    uint16_t mXLen;
    uint16_t mSI;
    uint16_t mSLen;
    uint16_t mBlockSizeLessOne;

    static uint16_t const BGZF_ID = 0x8b1f;
    static uint8_t const BGZF_CM = 8;
    static uint8_t const BGZF_FHCRC = 0x02;
    static uint8_t const BGZF_FXTRA = 0x04;
    static uint8_t const BGZF_FNAME = 0x08;
    static uint8_t const BGZF_FCMNT = 0x10;
    static uint16_t const BGZF_XLEN = 6;
    static uint16_t const BGZF_SI = 0x4342;
    static uint16_t const BGZF_SLEN = 2;
};

// image of the end of a GZip block -- the part after the compressed data
struct GZipFooter
{
    GZipFooter( char const* pData )
    { memcpy(this,pData,sizeof(*this)); }

    GZipFooter( z_stream const& zs )
    { uint8_t const* pBuf = zs.next_out-zs.total_out;
      mCRC32 = ::crc32(gEmptyCRC,pBuf,zs.total_out);
      mISize = zs.total_out; }

    friend bool operator!=( GZipFooter const& ftr1, GZipFooter const& ftr2 )
    { return ftr1.mCRC32 != ftr2.mCRC32 || ftr1.mISize != ftr2.mISize; }

    uint32_t mCRC32;
    uint32_t mISize;
    static uint32_t gEmptyCRC;
};

uint32_t GZipFooter::gEmptyCRC = ::crc32(0,nullptr,0);

// image of the header for a BAM file
struct BAMAlignHead
{
    uint32_t mRemainingBlockSize;
    int32_t mRefID;
    int32_t mPos;
    uint8_t mNameLen;
    uint8_t mMapQ;
    uint16_t mBin;
    uint16_t mCigarLen;
    uint16_t mFlags;
    uint32_t mSeqLen;
    int32_t mMateRefID;
    int32_t mMatePos;
    int32_t mTLen;

    // length of the alignment data excluding the header
    uint32_t remainingLen() const
    { return mRemainingBlockSize - sizeof(BAMAlignHead)
                + sizeof(mRemainingBlockSize); }

    bool isFirstRead() const
    { return (mFlags & FLAG_FIRST_SEGMENT) && !(mFlags & FLAG_LAST_SEGMENT); }

    bool isSecondRead() const
    { return (mFlags & FLAG_LAST_SEGMENT) && !(mFlags & FLAG_FIRST_SEGMENT); }

    static uint16_t const FLAG_REVERSED = 0x10;
    static uint16_t const FLAG_FIRST_SEGMENT = 0x40;
    static uint16_t const FLAG_LAST_SEGMENT = 0x80;
    static uint16_t const FLAG_PF = 0x200;
    static uint16_t const FLAG_SECONDARY_ALIGNMENT = 0x900;
};

// auxiliary tags signal the data type of the tag with these characters
// a return of 0 means "variable length"
// a return of -1 means "illegal data type specifier"
inline int getTagLength( char dataType )
{
    int tagLen;
    switch ( dataType )
    {
    case 'A': case 'c': case 'C': tagLen = 1; break;
    case 's': case 'S':           tagLen = 2; break;
    case 'i': case 'I': case 'f': tagLen = 4; break;
    case 'Z': case 'H': case 'B': tagLen = 0; break;
    default:                      tagLen = -1; break;
    }
    return tagLen;
}

char const* RTFM =
".\n"
"Please validate your BAM file with standard tools such as the Picard tool\n"
" ValidateSamFile. To do this, first make sure you have\n"
"java installed on your server and in your path.\nThen find the bin directory"
" for Picard jar files, denoted here picard-bin.\n"
"Finally, execute the command\n"
"java -jar picard-bin/ValidateSamFile.jar my.bam\n"
"where my.bam is the name of your bam file.\n";

#define BAMERR(file,message)  \
     { std::cout << "\nBAM file " << file << message << RTFM; Scram(1); }

#if 0
// single-threaded version is slower
class BAMbuf : public std::streambuf
{
public:
    BAMbuf( String const& bamFile ) : mFR(bamFile), mBlockNo(0)
    { char* end = &mInfBuf.back(); setg(&mInfBuf.front(),end,end); }

    BAMbuf( BAMbuf const& )=delete;
    BAMbuf& operator=( BAMbuf const& )=delete;

private:
    int_type underflow() override;
    bool readBlock();

    static size_t const FIL_BUF_SIZ = 64*1024ul;
    static size_t const INF_BUF_SIZ = 256*1024ul;

    FileReader mFR;
    size_t mBlockNo;
    std::array<char,FIL_BUF_SIZ> mFilBuf;
    std::array<char,INF_BUF_SIZ> mInfBuf;
};

std::streambuf::int_type BAMbuf::underflow()
{
    while ( gptr() == egptr() )
    {
        *eback() = gptr()[-1];
        if ( !readBlock() )
            return traits_type::eof();
    }
    return traits_type::to_int_type(*gptr());
}

bool BAMbuf::readBlock()
{
    size_t nRead;
    char* filBuf = &mFilBuf.front();
    GZipHeader const& hdr = *reinterpret_cast<GZipHeader*>(filBuf);
    if ( (nRead = mFR.readSome(filBuf,sizeof(hdr))) != sizeof(hdr) )
    {
        if ( !nRead ) return false;
        BAMERR(mFR.getFilename(),
                " is corrupt.  Partial GZIP header at block " << mBlockNo+1);
    }
    ++mBlockNo;
    if ( !hdr.isBGZFBlock() )
        BAMERR(mFR.getFilename(),
                " is uninterpretable as BGZF at block " << mBlockNo);

    char* itr = filBuf + sizeof(hdr);
    char* end = filBuf + hdr.getBlockLen();
    size_t remain = end - itr;
    if ( (nRead = mFR.readSome(itr,remain)) != remain )
        BAMERR(mFR.getFilename()," is truncated in block " << mBlockNo);

    if ( hdr.hasFName() )
        itr += strlen(itr)+1;
    if ( hdr.hasComment() )
        itr += strlen(itr)+1;
    if ( hdr.hasHdrCRC() )
        itr += 2;

    end -= sizeof(GZipFooter);
    if ( itr == end )
        return true; // read an empty block
    else if ( itr > end )
        BAMERR(mFR.getFilename(),
                " has bogus block length at block " << mBlockNo);

    z_stream zs;
    zs.zalloc = nullptr;
    zs.zfree = nullptr;
    zs.opaque = nullptr;
    zs.data_type = Z_BINARY;
    zs.next_in = reinterpret_cast<uint8_t*>(itr);
    zs.avail_in = end-itr;
    zs.next_out = reinterpret_cast<uint8_t*>(&mInfBuf[1]);
    zs.avail_out = INF_BUF_SIZ-1;

    if ( ::inflateInit2(&zs,-15) != Z_OK ||
         ::inflate(&zs,Z_FINISH) != Z_STREAM_END ||
         ::inflateEnd(&zs) != Z_OK ||
         GZipFooter(end) != GZipFooter(zs) ||
         zs.avail_in )
        BAMERR(mFR.getFilename(),
                " can't be unzipped at block " << mBlockNo);

    char* gptr = reinterpret_cast<char*>(zs.next_out-zs.total_out);
    setg( &mInfBuf.front(), gptr, gptr+zs.total_out );
    return true;
}
#endif

// a streambuf that grabs the next decompressed BGZF block on underflow.
// this version uses one thread to unzip while the main thread reads aligns.
// it appears that unzipping is just a bit slower than processing aligns.
class BAMbuf : public std::streambuf
{
public:
    BAMbuf( String const& bamFile )
    : mFR(bamFile), mBlockNo(0), mBufAvailable(mLock), mBufConsumed(mLock),
      mBeg(nullptr), mNext(nullptr), mEnd(nullptr), mQuit(false),
      mUnzipThread([this](){unzipBlocks();})
    { char* end = &mInfBuf[0].back(); setg(&mInfBuf[0].front(),end,end); }

    BAMbuf( BAMbuf const& )=delete;

    ~BAMbuf()
    { if ( true )
      { Locker locker(mLock); mQuit = true; mBeg = nullptr; }
      mBufConsumed.signal(); mUnzipThread.join(); }

    BAMbuf& operator=( BAMbuf const& )=delete;

private:
    int_type underflow() override;
    void unzipBlocks();
    bool offerBuf( char* beg, char* next, char* end )
    {
        Locker locker(mLock);
        while ( mBeg )
            locker.wait(mBufConsumed);
        if ( mQuit )
            return true;
        mNext = next;
        mEnd = end;
        mBeg = beg;
        return false;
    }

    static size_t const FIL_BUF_SIZ = 64*1024ul;
    static size_t const INF_BUF_SIZ = 256*1024ul;

    FileReader mFR;
    size_t mBlockNo;
    std::array<char,FIL_BUF_SIZ> mFilBuf;
    std::array<char,INF_BUF_SIZ> mInfBuf[3];
    LockedData mLock;
    Condition mBufAvailable;
    Condition mBufConsumed;
    char* mBeg;
    char* mNext;
    char* mEnd;
    bool mQuit;
    std::thread mUnzipThread;
};

std::streambuf::int_type BAMbuf::underflow()
{
    if ( gptr() == egptr() )
    {
        char putBackChr = gptr()[-1];
        if ( true )
        {
            Locker locker(mLock);
            while ( !mBeg )
                locker.wait(mBufAvailable);
            if ( mNext == mEnd )
                return traits_type::eof();
            setg(mBeg,mNext,mEnd);
            mBeg = nullptr;
        }
        mBufConsumed.signal();
        *eback() = putBackChr;
    }
    return traits_type::to_int_type(*gptr());
}

void BAMbuf::unzipBlocks()
{
    size_t bufId = 0;
    while ( true )
    {
        char* infBuf = &mInfBuf[bufId].front();
        size_t nRead;
        char* filBuf = &mFilBuf.front();
        GZipHeader const& hdr = *reinterpret_cast<GZipHeader*>(filBuf);
        if ( (nRead = mFR.readSome(filBuf,sizeof(hdr))) != sizeof(hdr) )
        {
            if ( !nRead )
            {
                if ( !offerBuf(infBuf,infBuf,infBuf) )
                    mBufAvailable.signal();
                break;
            }
            BAMERR(mFR.getFilename(),
                    " is corrupt.  Partial GZIP header at block " << mBlockNo+1);
        }
        ++mBlockNo;
        if ( !hdr.isBGZFBlock() )
            BAMERR(mFR.getFilename(),
                    " is uninterpretable as BGZF at block " << mBlockNo);

        char* itr = filBuf + sizeof(hdr);
        char* end = filBuf + hdr.getBlockLen();
        size_t remain = end - itr;
        if ( (nRead = mFR.readSome(itr,remain)) != remain )
            BAMERR(mFR.getFilename()," is truncated in block " << mBlockNo);

        if ( hdr.hasFName() ) itr += strlen(itr)+1;
        if ( hdr.hasComment() ) itr += strlen(itr)+1;
        if ( hdr.hasHdrCRC() ) itr += 2;

        end -= sizeof(GZipFooter);
        if ( itr == end ) continue; // read an empty block
        else if ( itr > end )
            BAMERR(mFR.getFilename(),
                    " has bogus block length at block " << mBlockNo);

        z_stream zs;
        zs.zalloc = nullptr;
        zs.zfree = nullptr;
        zs.opaque = nullptr;
        zs.data_type = Z_BINARY;
        zs.next_in = reinterpret_cast<uint8_t*>(itr);
        zs.avail_in = end-itr;
        zs.next_out = reinterpret_cast<uint8_t*>(infBuf+1);
        zs.avail_out = INF_BUF_SIZ-1;

        if ( ::inflateInit2(&zs,-15) != Z_OK ||
                ::inflate(&zs,Z_FINISH) != Z_STREAM_END ||
                ::inflateEnd(&zs) != Z_OK ||
                GZipFooter(end) != GZipFooter(zs) ||
                zs.avail_in )
            BAMERR(mFR.getFilename(),
                    " can't be unzipped at block " << mBlockNo);

        if ( zs.total_out )
        {
            char* next = reinterpret_cast<char*>(zs.next_out-zs.total_out);
            if ( offerBuf(infBuf,next,next+zs.total_out) ) break;
            mBufAvailable.signal();
            if ( ++bufId == 3 ) bufId = 0;
        }
    }
}

// read over the header and dictionary part of a BAM file, leaving us
// positioned at the alignments section

void skipToAligns( std::istream& is, String const& bamFile )
{
    uint32_t val;
    if ( !is.read(reinterpret_cast<char*>(&val),sizeof(val)) )
        BAMERR(bamFile," is empty");
    if ( val != 0x014d4142 )
        BAMERR(bamFile," lacks a BAM header");
    if ( !is.read(reinterpret_cast<char*>(&val),sizeof(val)) )
        BAMERR(bamFile," header length is truncated");
    if ( !is.ignore(val) )
        BAMERR(bamFile," is truncated in header");
    uint32_t nRefs;
    if ( !is.read(reinterpret_cast<char*>(&nRefs),sizeof(nRefs)) )
        BAMERR(bamFile," is truncated at ref desc count");
    while ( nRefs-- )
    {
        if ( !is.read(reinterpret_cast<char*>(&val),sizeof(val)) )
            BAMERR(bamFile," is truncated in ref desc len");
        if ( !is.ignore(val) )
            BAMERR(bamFile," is truncated at ref desc name");
        if ( !is.read(reinterpret_cast<char*>(&val),sizeof(val)) )
            BAMERR(bamFile," is truncated in ref desc size");
    }
}

void readAligns( std::istream& is, const String& bamFile,
        MempoolAllocator<char> const& alloc, bool pfOnly,
        vecbasevector& reads_b, VecPQVec& reads_q, vecString& reads_n )
{
     // Buffer for quality score compression in batches.

     // VecPQVec qualsbuf_c;
     const int qbmax = 10000000;
     vec<qvec> qualsbuf;
     for ( int i = 0; i < qbmax; i++ )
          qualsbuf.emplace_back(alloc);
     int qbcount = 0;

     BAMAlignHead alnHd;
     size_t alnNo = 0;
     RNGen rng;
     std::vector<char> nibbleSeq;
     while ( !is.eof() && is.peek() != std::istream::traits_type::eof() )
     {    ++alnNo;
          if ( !is.read(reinterpret_cast<char*>(&alnHd), sizeof(alnHd)) )
               BAMERR(bamFile," is truncated in alignment " << alnNo);
          if ( (pfOnly && !(alnHd.mFlags & BAMAlignHead::FLAG_PF)) ||
               (alnHd.mFlags & BAMAlignHead::FLAG_SECONDARY_ALIGNMENT) )
          {    if ( !is.ignore(alnHd.remainingLen()) )
                    BAMERR(bamFile," is truncated in skipped alignment " << alnNo);
               continue;    }

          reads_b.push_back( basevector(alloc) );
          reads_n.push_back( String(alloc) );

          basevector& seq = reads_b.back();
          String& readName = reads_n.back();

          readName.reserve(alnHd.mNameLen + 1);
          readName.resize(alnHd.mNameLen - 1);
          if ( !is.read(&readName.front(), alnHd.mNameLen - 1) || !is.ignore(1) )
               BAMERR(bamFile," is truncated in read name of alignment " << alnNo);
          readName.push_back('.');
          if ( alnHd.isFirstRead() ) readName.push_back('1');
          else if ( alnHd.isSecondRead() ) readName.push_back('2');
          else readName.push_back('3');

          if ( !is.ignore(4 * alnHd.mCigarLen) )
               BAMERR(bamFile," is truncated in cigar of alignment " << alnNo);

          seq.reserve(alnHd.mSeqLen);
          nibbleSeq.resize((alnHd.mSeqLen+1)/2);
          char* nibbles = &nibbleSeq.front();
          if ( !is.read(nibbles,nibbleSeq.size()) )
              BAMERR(bamFile," is truncated in seq of alignment " << alnNo);
          char packedSeq = 0;
          for ( unsigned idx = 0; idx != alnHd.mSeqLen; ++idx )
          {   if ( idx & 1 ) packedSeq <<= 4;
              else packedSeq = *nibbles++;
              char bits = (packedSeq >> 4) & 0x0f;
              if ( !bits )
                  BAMERR(bamFile," has uninterpretable seq data in alignment "
                              << alnNo);
              seq.push_back(GeneralizedBase::fromBits(bits).random(rng));    }

        qvec& quals = qualsbuf[qbcount];
        qbcount++;
        quals.resize(alnHd.mSeqLen);
        char* qBuf = reinterpret_cast<char*>(&quals.front());
        if ( !is.read(qBuf,alnHd.mSeqLen) )
            BAMERR(bamFile," is truncated in quals of alignment " << alnNo);

        long auxLen = alnHd.remainingLen() - alnHd.mNameLen
                    - 4*alnHd.mCigarLen - (alnHd.mSeqLen + 1)/2 - alnHd.mSeqLen;
        while ( auxLen > 0 )
        {
            char tag[3];
            if ( !is.read(tag, sizeof(tag)) )
                BAMERR(bamFile," is truncated in tag header for alignment "
                        << alnNo);
            auxLen -= 3;
            int tagLen = getTagLength(tag[2]);
            if ( tagLen == -1 )
                BAMERR(bamFile," has bad data type in tag header for alignment "
                        << alnNo);
            if ( tag[2] == 'B' )
            {
                char dataType;
                uint32_t arrLen;
                if ( !is.get(dataType)
                        || !is.read(reinterpret_cast<char*>(&arrLen),
                                sizeof(arrLen)) )
                    BAMERR(bamFile,
                            " is truncated in B tag header for alignment "
                               << alnNo);
                tagLen = getTagLength(dataType);
                if ( tagLen <= 0 )
                    BAMERR(bamFile,
                            " has bad data type in B tag header for alignment "
                                << alnNo);
                tagLen *= arrLen;
                auxLen -= 5;
            }

            if ( tagLen )
            {
                if ( !is.ignore(tagLen) )
                    BAMERR(bamFile," is truncated in tag data for alignment "
                                << alnNo);
                auxLen -= tagLen;
            }
            else if ( tag[0] == 'O' && tag[1] == 'Q' )
            {
                if ( tag[2] != 'Z' )
                    BAMERR(bamFile," contains OM tag with non-Z data type "
                                    "for alignment " << alnNo);
                if ( !is.read(qBuf,alnHd.mSeqLen) )
                    BAMERR(bamFile," is truncated in OM tag"
                                    " data for alignment " << alnNo);
                for ( unsigned char& val : quals )
                    val -= 33;
                char byte;
                if ( !is.get(byte) || byte )
                    BAMERR(bamFile," contains OM tag with the wrong length "
                                    "for alignment " << alnNo);
                auxLen -= alnHd.mSeqLen + 1;
            }
            else // has to be H or Z tag type
            {    char byte;
                 do
                 {    if ( !is.get(byte) )
                           BAMERR(bamFile," is truncated in null-delimited tag"
                                        " data for alignment " << alnNo);
                      auxLen -= 1;    }
                 while ( byte );    }
        }

     if ( auxLen < 0 )
          BAMERR(bamFile," has bogus alignment block len for alignment " << alnNo);

     if ( alnHd.mFlags & BAMAlignHead::FLAG_REVERSED )
     {    seq.ReverseComplement( );
          quals.ReverseMe( );    }

     // Convert a batch of quality scores.

     if ( qbcount == qbmax )
     {    convertAppendParallel( qualsbuf.begin( ), qualsbuf.begin( ) + qbcount,
               reads_q );
          qbcount = 0;     }

    }

     // Convert final batch of quality scores.

     convertAppendParallel( qualsbuf.begin( ), qualsbuf.begin( ) + qbcount,
          reads_q );

}

class FunnyIterator
{
public:
    FunnyIterator( qvec const** pVals ) : mpVals(pVals) {}
    qvec const& operator*() { return **mpVals; }
    qvec const* operator->() { return *mpVals; }
    FunnyIterator& operator++() { ++mpVals; return *this; }
    friend FunnyIterator operator+( FunnyIterator const& fi, size_t off )
    { return FunnyIterator(fi.mpVals+off); }
    friend size_t operator-( FunnyIterator const& fi1, FunnyIterator const& fi2 )
    { return fi1.mpVals - fi2.mpVals; }
    friend bool operator!=( FunnyIterator const& fi1, FunnyIterator const& fi2 )
    { return fi1.mpVals != fi2.mpVals; }

private:
    qvec const** mpVals;
};

template <class T> void movePairs( size_t nReads, vecbasevector& reads_b,
     VecPQVec& reads_q, vecString& reads_n, vec<T> const& readIndices,
     bool uniquifyNames, vecbvec* pVBV, VecPQVec* pVPQV, vecString* pReadNames )
{
     size_t nPairs = (nReads + 1)/2;
     if (pReadNames)
     {    pReadNames->reserve(pReadNames->size() + nReads);
          auto prev = readIndices.begin();
          auto end = readIndices.end();
          for ( auto itr = prev+1; itr != end; ++itr,++prev )
          {    String const& name1 = reads_n[*prev];
               String const& name2 = reads_n[*itr];
               if ( name1.size() == name2.size() &&
                    std::equal(name1.begin(),name1.end()-2,name2.begin()) )
               {    if (uniquifyNames)
                    {    pReadNames->push_back(name1);
                         char& last1 = pReadNames->back().back();
                         if ( last1 == '3' ) last1 = '1';
                         pReadNames->push_back(name2);
                         char& last2 = pReadNames->back().back();
                         if ( last2 == '3' ) last2 = '2';    }
                    else
                    {    pReadNames->push_back(String(name1.begin(),name1.end()-2));
                         pReadNames->push_back(String(name2.begin(),name2.end()-2));
                             }    }
               ++prev;
               if ( ++itr == end || !--nPairs ) break;    }    }
     vec<T> ids;
     {    auto prev = readIndices.begin();
          auto end = readIndices.end();
          for ( auto itr = prev+1; itr != end; ++itr,++prev )
          {    String const& name1 = reads_n[*prev];
               String const& name2 = reads_n[*itr];
               if ( name1.size() == name2.size() &&
                    std::equal(name1.begin(),name1.end()-2,name2.begin()) )
               {    ids.push_back( prev - readIndices.begin( ) );
                    ++prev;
                    if ( ++itr == end || !--nPairs ) break;    }    }    }
     Destroy(reads_n);
     pVBV->reserve(pVBV->size() + nReads);
     for ( int64_t i = 0; i < ids.jsize( ); i++ )
     {    pVBV->push_back( reads_b[ readIndices[ ids[i] ] ] );
          pVBV->push_back( reads_b[ readIndices[ ids[i] + 1 ] ] );    }
     Destroy(reads_b);
     pVPQV->reserve(pVPQV->size() + nReads);
     for ( int64_t i = 0; i < ids.jsize( ); i++ )
     {    pVPQV->push_back( reads_q[ readIndices[ ids[i] ] ] );
          pVPQV->push_back( reads_q[ readIndices[ ids[i] + 1 ] ] );    }
     Destroy(reads_q);    }

} // end of anonymous namespace

void BAMReader::readBAM( String const& bamFile,
                         vecbvec* pVBV, VecPQVec* pVPQV, vecString* pReadNames )
{
    std::cout << Date( ) << ": processing " << bamFile << '.' << std::endl;
    std::cout << Date( ) << ": memory in use = " << MemUsageGBString( )
#ifdef __linux
          << ", peak = " << PeakMemUsageGBString( )
#endif
          << std::endl;
    vecbasevector reads_b;
    VecPQVec reads_q;
    vecString reads_n;
    BAMbuf* pBB = new BAMbuf(bamFile);
    {    std::istream is(pBB);
         skipToAligns(is,bamFile);
         MempoolOwner<char> alloc;
         reads_b.reserve(100000000);
         reads_q.reserve(100000000);
         reads_n.reserve(100000000);
         readAligns(is, bamFile, alloc, mPFOnly, reads_b, reads_q, reads_n);    }
    delete pBB;

    size_t nReads = std::min(size_t(mSelectFrac*reads_b.size()),mReadsToUse);
    int64_t length_sum = 0;
    for ( int64_t i = 0; i < (int64_t) reads_b.size( ); i++ )
         length_sum += reads_b[i].size( );
    //[GONZA] remove ToStringAddCommas
    std::cout << Date( ) << ": there are " << nReads << " reads";
    if ( reads_b.size( ) > 0 )
    {    int64_t len = length_sum / reads_b.size( );
         std::cout << " of mean length " << len << std::endl;    }
    else std::cout << std::endl;
    std::cout << Date( ) << ": memory in use = " << MemUsageGBString( )
#ifdef __linux
        << ", peak = " << PeakMemUsageGBString( )
#endif
        << std::endl;
    nReads = (nReads + 1ul) & ~1ul;
    if ( !nReads ) return;
    if ( (int64_t) reads_b.size( ) < UINT32_MAX )
    {    vec<uint32_t> readIndices(rangeItr(0ul),rangeItr(reads_b.size()));
         ParallelSort( readIndices, [&reads_n]( size_t idx1, size_t idx2 )
              { return reads_n[idx1] < reads_n[idx2]; } );
         std::cout << Date( ) << ": reads sorted" << std::endl;
         std::cout << Date( ) << ": memory in use = " << MemUsageGBString( )
#ifdef __linux
            << ", peak = " << PeakMemUsageGBString( )
#endif
            << std::endl;
         movePairs( nReads, reads_b, reads_q, reads_n, readIndices,
              mUniquifyNames, pVBV, pVPQV, pReadNames );    }
    else
    {    vec<uint64_t> readIndices(rangeItr(0ul),rangeItr(reads_b.size()));
         ParallelSort( readIndices, [&reads_n]( size_t idx1, size_t idx2 )
              { return reads_n[idx1] < reads_n[idx2]; } );
         std::cout << Date( ) << ": reads sorted" << std::endl;
         std::cout << Date( ) << ": memory in use = " << MemUsageGBString( )
#ifdef __linux
            << ", peak = " << PeakMemUsageGBString( )
#endif
            <<std::endl;
         movePairs( nReads, reads_b, reads_q, reads_n, readIndices,
              mUniquifyNames, pVBV, pVPQV, pReadNames );    }
    std::cout << Date( ) << ": data stashed in output structures" << std::endl;
    std::cout << Date( ) << ": memory in use = " << MemUsageGBString( )
#ifdef __linux
        << ", peak = " << PeakMemUsageGBString( )
#endif
        <<std::endl;
}


text:
static bool eigen_did_assert = false;
#define eigen_assert(X) if(!eigen_did_assert && !(X)){ std::cout << "### Assertion raised in " << __FILE__ << ":" << __LINE__ << ":\n" #X << "\n### The following would happen without assertions:\n"; eigen_did_assert = true;}

#include <iostream>
#include <Eigen/Eigen>

#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif

using namespace Eigen;
using namespace std;

int main(int, char**)
{
  cout.precision(3);
  MatrixXcd X = MatrixXcd::Random(4,4);
MatrixXcd A = X + X.adjoint();
cout << "Here is a random self-adjoint 4x4 matrix:" << endl << A << endl << endl;

Tridiagonalization<MatrixXcd> triOfA(A);
MatrixXd T = triOfA.matrixT();
cout << "The tridiagonal matrix T is:" << endl << T << endl << endl;

cout << "We can also extract the diagonals of T directly ..." << endl;
VectorXd diag = triOfA.diagonal();
cout << "The diagonal is:" << endl << diag << endl;
VectorXd subdiag = triOfA.subDiagonal();
cout << "The subdiagonal is:" << endl << subdiag << endl;

  return 0;
}


text:
[![Gem Version](https://badge.fury.io/rb/velocify.svg)](http://badge.fury.io/rb/velocify)
[![Code Climate](https://codeclimate.com/github/pennymac/velocify/badges/gpa.svg)](https://codeclimate.com/github/pennymac/velocify)
[![Build Status](https://travis-ci.org/pennymac/velocify.svg)](https://travis-ci.org/pennymac/velocify)
[![Test Coverage](https://codeclimate.com/github/pennymac/velocify/badges/coverage.svg)](https://codeclimate.com/github/pennymac/velocify/coverage)

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'velocify'
```

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install velocify

## Usage

Before getting started, you must export two environment variables: ```VELOCIFY_USERNAME``` and ```VELOCIFY_PASSWORD```.
This gem uses Dotenv, so you can add these variables to your ```.env``` file in the root folder of your project.

You can also programmatically configure the username and password:

``` ruby
Velocify.configure do |config|
  config.username = "myusername"
  config.password = "mypassword"
end
```

``` ruby
require 'velocify'

statuses = Velocify::Status.find_all
# => {statuses=>status=>[{...}, ...]}

dormant_id = Velocify::ResponseReader.read(kind: :status, response: statuses).find_id_by_title 'Dormant'
# => 31

statuses_with_name = Velocify::ResponseReader.read(kind: :status, response: statuses).search_by_title 'Name'
# => [{...}, ...]

leads = Velocify::Lead.find_last_created
# => {leads=>lead=>{...}}

# There's also support for destructuring

success, leads = Velocify::Lead.find_all from: '2000-01-01T00:00:00', to: '2000-02-01T00:00:00', destruct: true
# => [true, {leads=>lead=>[{...}]}]
success
# => true
payload
# => {leads=>lead=>[{ ... }]}

# You can even have your results returned as an array

success, leads = Velocify::Lead.find_all from: '2000-01-01T00:00:00', to: '2000-02-01T00:00:00', destruct: true, return_array: true
# => [true, [{...}, ... }]

# Pushing leads to Velocify
campaign_id = Velocify::ResponseReader.read(kind: :campaign, response: Velocify::Campaign.find_all).find_id_by_title 'Test Campaign'
status_id = Velocify::ResponseReader.read(kind: :status, response: Velocify::Status.find_all).find_id_by_title 'Active'
last_name_id = Velocify::ResponseReader.read(kind: :field, response: Velocify::Field.find_all).find_id_by_title 'Last Name'
first_name_id = Velocify::ResponseReader.read(kind: :field, response: Velocify::Field.find_all).find_id_by_title 'First Name'

lead = Velocify::Lead.new
lead.campaign_id = campaign_id
lead.status_id = status_id
lead.add_field id: first_name_id, value: "Joe"
lead.add_field id: last_name_id, value: "Bo"

Velocify::Lead.add leads: [ lead ]
```

## Changes

For a list of changes in each release, read the CHANGELOG.

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/pennymac/velocify. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.

## License

The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).


text:
import unittest

import httpstatus

class HTTPhttpstatusTest(unittest.TestCase):

    def test_lt(self):
        self.assertFalse(httpstatus.HTTP_200_OK < 199)
        self.assertFalse(httpstatus.HTTP_200_OK < 200)
        self.assertTrue(httpstatus.HTTP_200_OK < 201)

    def test_le(self):
        self.assertFalse(httpstatus.HTTP_200_OK <= 199)
        self.assertTrue(httpstatus.HTTP_200_OK <= 200)
        self.assertTrue(httpstatus.HTTP_200_OK <= 201)

    def test_eq(self):
        self.assertEqual(httpstatus.HTTP_200_OK, 200)
        self.assertEqual(200, httpstatus.HTTP_200_OK)

    def test_ne(self):
        self.assertNotEqual(httpstatus.HTTP_200_OK, 201)
        self.assertNotEqual(201, httpstatus.HTTP_200_OK)

    def test_gt(self):
        self.assertTrue(httpstatus.HTTP_200_OK > 199)
        self.assertFalse(httpstatus.HTTP_200_OK > 200)
        self.assertFalse(httpstatus.HTTP_200_OK > 201)

    def test_ge(self):
        self.assertTrue(httpstatus.HTTP_200_OK >= 199)
        self.assertTrue(httpstatus.HTTP_200_OK >= 200)
        self.assertFalse(httpstatus.HTTP_200_OK >= 201)

    def test_int(self):
        httpstatus_int = int(httpstatus.HTTP_200_OK)
        self.assertTrue(type(httpstatus_int) == int)
        self.assertTrue(httpstatus_int == 200)

    def test_str(self):
        httpstatus_str = str(httpstatus.HTTP_200_OK)
        self.assertTrue(type(httpstatus_str) == str)
        self.assertTrue(httpstatus_str == 'HTTP 200 - OK')

    def test_is_informational(self):
        self.assertTrue(httpstatus.is_informational(httpstatus.HTTP_100_CONTINUE))
        self.assertTrue(httpstatus.is_informational(100))

    def test_is_success(self):
        self.assertTrue(httpstatus.is_success(httpstatus.HTTP_200_OK))
        self.assertTrue(httpstatus.is_success(200))

    def test_is_redirect(self):
        self.assertTrue(httpstatus.is_redirect(httpstatus.HTTP_300_MULTIPLE_CHOICES))
        self.assertTrue(httpstatus.is_redirect(300))

    def test_is_client_error(self):
        self.assertTrue(httpstatus.is_client_error(httpstatus.HTTP_400_BAD_REQUEST))
        self.assertTrue(httpstatus.is_client_error(400))

    def test_is_server_error(self):
        self.assertTrue(httpstatus.is_server_error(httpstatus.HTTP_500_INTERNAL_SERVER_ERROR))
        self.assertTrue(httpstatus.is_server_error(500))

if __name__ == '__main__':
    unittest.main()


text:
layout: post
title: "PC to GBA interface -- Part 1"
categories: blog
excerpt:
tags: []
image:
  feature:
date: 2019-10-13 23:43:17 +0200
modified: 2019-10-13 23:43:17 +0200
---

A little while ago I tweeted about a project where I was showing the picture of a GameBoy Advance (GBA) on which I soldered a few cables onto the serial port. The idea behind this was to make an interface between the GBA and my computer so that I could use it as an alternative controller and screen.
This post is more a log book rather than a straight to the point technical document. I like to tell stories and I believe showing the errors made and paths taken is always interesting.

![tweet pic](/images/posts/pc2gba/tweetpic.jpg "GBA hydrabus sniffing")

# Introduction

I woke up one day with the revelation that some Nintendo GameCube (GC) games allow the use of a GBA as a controller, using a particular cable. This configurations also permits the GC to display images or game data directly on the GBA.
This triggered two things in my brain: the need to know how it works, and of course I wanted to be able to do it from my computer because, you know... why not?!

At the time of writing, I have made some progress but my goal isn't yet reached. This post is only the beggining and I don't know when I'll finish. However I thought that I should share the informations and experimentations I've done until now.

## Zelda four sword adventure

When I was younger I bought this GameCube game: Zelda four sword adventure. It was great, and as a Zelda fan I liked it a lot! And yes I still have it to this day! :D

![zelda four sword adventure](/images/posts/pc2gba/zelda4swda.jpg "Zelda: four sword adventure")

But the important thing about this game is that little yellow stamp that you can see on the bottom left, next to the PEGI sign.
If you add a GBA and the cable to connect it to the GC, it was possible to play using the GBA as a controller. And even better, if you use this, when entering a room, the room's screen was displayed on the GBA screen while the outside was still on the TV!

![zelda in game](/images/posts/pc2gba/zeldaingame.jpg "Zelda in game")

Now that I think about it, Nintendo had the idea for the Wii U and the Switch a long time ago!

## GC <-> GBA Cable link

For those of you who never saw that cable, here it is: [NGC to GBA link cable](https://en.wikipedia.org/wiki/GameCube_%E2%80%93_Game_Boy_Advance_link_cable)

# RE: sniffing the lines!

The first idea that came to my mind when trying to understand how it is done was to sniff the data on the cable. Looking back, this might not have been the best idea but it was fun to explore nonetheless.

## Soldering time

### EXT port

Well, I don't really know what to say except that: it's ugly but it works ¯\\_(ツ)_/¯

![soldering EXT port](/images/posts/pc2gba/soldering.jpg "EXT port GBA soldering")

And here is the mapping for future references:

|PIN| EXT port         | Cable color |
|---|------------------|-------------|
|1  | Vcc              | Green       |
|2  | SO (serial out)  | Red         |
|3  | SI (serial in)   | Blue        |
|4  | SD (serial data) | Orange      |
|5  | SC {serial clock)| Purple      |
|6  | GND              | Yellow      |

GBA socket:

```
 ___________
|  2  4  6  |
 \_1_ 3 _5_/
     '-'
```

### Bonus: batteries are lame

It was really unpractical to perform my tests using batteries and since we need to switch the GBA on before receiving any data, I soldered two more wires on it so I could use the hydrabus' 3.3v and GND lines instead.

## Reading some data

Now, as you might have guessed, I used my hydrabus in SUMP mode to sniff the wires.

### Configuration

#### Pluging things in the right place

This is the easy part, I just plugged the wires I soldered on the EXT port to the hydrabus with the help of the [great documentation about hydrabus' SUMP mode](https://github.com/hydrabus/hydrafw/wiki/HydraFW-SUMP-guide).

#### Pulseview

For the software part, I chose to use [sigrok](https://sigrok.org/) along with the [pulseview](https://sigrok.org/wiki/PulseView) interface.

To use the hydrabus as the hardware interface for pulseview, we uses the following configuration:

![pulseview config hydrabus](/images/posts/pc2gba/pulseviewconfig.png "Configuration of pulseview to use the hydrabus")

And finally we can customize our inputs to have a proper look.

![pulseviewready](/images/posts/pc2gba/pulseviewready.png "Pulseview channel configured")

### Getting data & limitations

One of the first thing you will learn if it is your first time doing this, is that the hydrabus is **not** a logic analyzer and **can not** stream everything to your computer.
In fact, it has an internal buffer that can store a few samples and sends it to the computer when the buffer is full. So here is one of our first limitation: we will only record chunks of the communication.

#### First frames

Okay, getting the first frames is easy: let's plug the GBA to the GC using the link cable, we then switch the GC on, running the game. Now click `run` in pulseview and switch the GBA on.
During my first attempt, I forgot to set a trigger on `Vcc` so all lines were low. After correcting this small mistake, we get the following data:

![initial capture](/images/posts/pc2gba/firstcapture2mhz.png "Initial capture at 2MHz")

Fair enough, let's get some more data and we'll analyse it all later!

#### Another chunk of frames

![capture 2MHz](/images/posts/pc2gba/capture2mhz.png "Another capture at 2MHz")

It looks about right, doesn't it? Well, sorry to spoil it for you, but no it isn't right. And this is were I encountered my first real issue with this process.

#### Limitations

What we see in those captures are signals recorded with a speed of 2MHz which is the maximum speed supported by the hydrabus. However, we can read on the specs of the GBA that its CPU runs at 16.8MHz. We are recording too slowly and many bits are missing from the captures.
This makes it impossible to analyse the protocol using this technique, and even more annoying: I might not be able to use the Hydrabus as my bridging interface between the computer and the GBA.

This made me rethink my original idea and I will find some solutions but in the meantime, I still want to know how this particular game manages to use the GBA as a controller. Let's reverse engineer the game!

# RE: analysing the game

## Getting the ISO

The first step to be able to reverse the game would be to have the game. On my computer. Please.
Apparently it requires either a Wii or some old and specific DVD reader to be able to read the mini disc and dump it to get an ISO. And, since I have neither and am curently short on money, I decided to download it from this wonderful place called **The Internet**.

Yup.

Actually, I would like to try to get the ISO by myself, but that will be in another post, maybe, eventually, hypothetically, someday.

## Extracting the crunchy data!

After reading about a bunch of tools (most of them dating back from the Windows XP era) I ended up learning that it was possible to extract the data using [dolphin-emu](https://dolphin-emu.org)

In order to do so:
* add the game to dolphin's library
* right-click -> properties
* go to the "Filesystem" tab
* right-click on disc -> "Extract files"

This produces two folder: `sys` and `files`

```bash
$ ll *
files:
total 8.0K
drwxr-xr-x 1 emy emy 1.8K Oct 12 09:09 GC4Sword_pal/
-rw-r--r-- 1 emy emy 8.0K Oct 12 08:25 opening.bnr

sys:
total 5.0M
-rw-r--r-- 1 emy emy 120K Oct 12 08:25 apploader.img
-rw-r--r-- 1 emy emy 8.0K Oct 12 08:25 bi2.bin
-rw-r--r-- 1 emy emy 1.1K Oct 12 08:25 boot.bin
-rw-r--r-- 1 emy emy 9.4K Oct 12 08:25 fst.bin
-rw-r--r-- 1 emy emy 4.9M Oct 12 08:25 main.dol
```

The `sys` folder contains the actual game program, here named `main.dol`. It appears that depending on the version of dolphin-emu, the sys files are not produced in the same manner. (I got a `boot.dol` on another computer)

```bash
$ file sys/*
apploader.img: data
bi2.bin:       data
boot.bin:      Nintendo GameCube disc image: "The Legend of Zelda: Four Swords FOR NINTENDO
GAMECUBE" (G4SP01, Rev.00)
fst.bin:       data
main.dol:      Apple HFS/HFS+ resource fork
```

From this point, sure, we could RE the main.dol file. But it's huge and I am lazy. And, I came to think about it, there probably is a GBA ROM somewhere that should be loaded directly on the GBA through the cable. Let's check the `files` directory.

```bash
 $ ll files/*
-rw-r--r-- 1 emy emy 8.0K Oct 12 08:25 files/opening.bnr

files/GC4Sword_pal:
total 16M
drwxr-xr-x 1 emy emy   34 Oct 12 08:25 Agb/
drwxr-xr-x 1 emy emy   62 Oct 12 08:25 AudioRes/
drwxr-xr-x 1 emy emy 6.4K Oct 12 08:25 Boss/
-rw-r--r-- 1 emy emy 3.3K Oct 12 08:25 cardicon.arc
drwxr-xr-x 1 emy emy   44 Oct 12 08:52 cardicon.arc_dir/
-rw-r--r-- 1 emy emy 1.2M Oct 12 08:25 data.arc
-rw-r--r-- 1 emy emy 136K Oct 12 08:25 entry.arc
-rw-r--r-- 1 emy emy 138K Oct 12 08:25 entryFrench.arc
[...]
```

DO YOU SEE IT??? Honnestly I was so tired it took me about 1 hour before I realized that `Agb` stands for `Advance GB`. This folder contains only a `client_thread.arc` file.
After a short amount of googling and staring this github repo: [ARCTool](https://github.com/tpwrules/ARCTool), I managed to get my hands on the shiny little piece of code I was looking for.

```bash
$ python2 ARCTool/ARCTool.py files/GC4Sword_pal/Agb/client_thread.arc
RARC archive
Processing node archive
Processing node agb
Dumping agb/client_thread.bin 100%

$ file client_thread.arc.extracted/archive/agb/client_thread.bin
client_thread.arc.extracted/archive/agb/client_thread.bin: Game Boy Advance ROM image (g4sp01, Rev.00)
```

Which can then be run in an emulator:
```bash
$ mgba client_thread.arc.extracted/archive/agb/client_thread.bin
```

![mgba client_thread](/images/posts/pc2gba/mgbaclient.png "Running the exctracted code with mgba")

And see you in part 2 for the actual reverse engineering :)

eq.


text:
'use strict';

// Contents of this plugin will be reset by Kite on start. Changes you make
// are not guaranteed to persist.

const vscode = require('vscode');
const dgram = require('dgram');
const crypto = require('crypto');

var PLUGIN_ID = null;
const SOURCE = "vscode";
const MAX_TEXT_SIZE = Math.pow(2, 20);

function activate (context) {
    console.log('KiteCode is now active');

    let incoming = new KiteIncoming();
    let outgoing = new KiteOutgoing();
    let eventController = new KiteEventController(incoming, outgoing);

    context.subscriptions.push(incoming);
    context.subscriptions.push(outgoing);
    context.subscriptions.push(eventController);
};

// Called when VSCode is shut down.
function deactivate () {
    console.log('bye');
};

// Builds a UDP bridge and listens for events from Kite.
var KiteOutgoing = class {
    static get HOST () {
        return "127.0.0.1";
    };

    static get PORT () {
        return 46625;
    };

    constructor () {
        this.outgoingSocket = dgram.createSocket("udp4");
    };

    // Builds a kite event based on action. An action being
    // an edit, a selection, or a focus.
    buildKiteEvent (action) {
        const editor = vscode.window.activeTextEditor;

        if (!editor) {
            return null;
        }

        let text = editor.document.getText();

        if (text.length > MAX_TEXT_SIZE) {
            return {
                "source": SOURCE,
                "action": "skip",
                "filename": editor.document.fileName,
                "text": "file_too_large",
                "pluginId": PLUGIN_ID,
            };
        }

        let cursorPoint = editor.selection.active;
        let cursorOffset = this.pointToOffset(text, cursorPoint);

        return {
            "source": SOURCE,
            "action": action,
            "filename": editor.document.fileName,
            "text": text,
            "pluginId": PLUGIN_ID,
            "selections": [{
                "start": cursorOffset,
                "end": cursorOffset,
            }],
        };
    };

    pointToOffset (text, point) {
        let lines = text.split("\n");
        var total = 0;

        for (var i = 0; i < lines.length && i < point.line; i++) {
            total += lines[i].length;
        }

        total += point.character + point.line;
        return total;
    };

    // Sends an event to Kite.
    sendEvent (action) {
        let event = this.buildKiteEvent(action);
        let msg = JSON.stringify(event);

        this.outgoingSocket.send(msg, 0, msg.length, KiteOutgoing.PORT, KiteOutgoing.HOST);
    };

    // Sends an error to Kite.
    sendError (data) {
        const editor = vscode.window.activeTextEditor;

        if (!editor) {
            return;
        }

        let event = {
            'source': SOURCE,
            'action': "error",
            'filename': editor.document.fileName,
            'text': JSON.stringify(data),
            'pluginId': PLUGIN_ID
        }

        let msg = JSON.stringify(event);
        this.outgoingSocket.send(msg, 0, msg.length, KiteOutgoing.PORT, KiteOutgoing.HOST);
    };

    // Fired on any edit event.
    onEdit (event) {
       this.sendEvent("edit");
    };

    // Fired when a user highlights or selects a keyword.
    onSelection (event) {
       this.sendEvent("selection");
    };

    // Fired when a user selects a different pane.
    onEditorChange (event) {
        this.sendEvent("focus");
    };
};

var KiteIncoming = class {
    constructor () {
        this.highlights = vscode.languages.createDiagnosticCollection("kite-highlights");

        this.incomingSocket = dgram.createSocket("udp4");
        this.incomingSocket.on('listening', this.listening.bind(this));
        this.incomingSocket.on('message', this.message.bind(this));
        this.incomingSocket.on('error', this.error.bind(this));
        this.incomingSocket.on('close', this.close.bind(this));

        this.incomingSocket.bind(0, "127.0.0.1");

        // Set in the event controller.
        this.kiteOutgoing = undefined;
    };

    listening () {
        let addr = this.incomingSocket.address();
        PLUGIN_ID = "udp://" + addr.address + ":" + addr.port;
        console.log("UDP Server listening on", PLUGIN_ID);
    };

    message (msg, rinfo) {
        let data = JSON.parse(msg.toString());
        this.handleSuggestion(data);
    };

    error (error) {
        console.log("UDP Server error:", error);
    };

    close () {
        console.log("Closing");
    };

    // Kite will send back suggestions. Depending on its type,
    // we handle it in one of three different ways:
    // an 'apply':
    //      - applies the suggested fix onto the active editor.
    // a 'highlight':
    //      - instructs the editor to highlight a range of code.
    // a 'clear':
    //      - instructs the editor to clear any highlights added
    //      to the editor.
    handleSuggestion (suggestion) {
        let suggestionType = suggestion['type'];
        if (suggestionType === 'apply') {
            this.handleApply(suggestion);
        } else if (suggestionType === 'highlight') {
            this.handleHighlight(suggestion);
        } else if (suggestionType === 'clear') {
            this.handleClear(suggestion);
        }
    };

    // Applies a suggested fix onto the currently active editor.
    handleApply (suggestion) {
        if (!this.validBuffer(suggestion)) {
            return;
        }

        const editor = vscode.window.activeTextEditor;

        if (!editor) {
            return;
        }

        for (var i = 0; suggestion.diffs && i < suggestion.diffs.length; i++) {
            let diff = suggestion.diffs[i];
            editor.edit(function (editBuilder) {
                let startPosition = new vscode.Position(diff.linenum - 1, 0);
                let endPosition = new vscode.Position(diff.linenum - 1, diff.line_src.length);
                let removedRange = new vscode.Range(startPosition, endPosition);
                editBuilder.replace(removedRange, diff.line_dest.trimRight());
            });
        }

        this.handleClear();
    };

    // Adds a highlight.
    handleHighlight (suggestion) {
        if (!this.validBuffer(suggestion)) {
            return;
        }

        const editor = vscode.window.activeTextEditor;

        if (!editor) {
            return;
        }

        let allHighlights = [];
        let documentUri = editor.document.uri;
        let documentText = editor.document.getText();

        for (var i = 0; suggestion.diffs && i < suggestion.diffs.length; i++) {
           let diff = suggestion.diffs[i];

           // Build the start and end position of the highlight before adding it.
           let offset = diff.end - diff.begin;
           let startPosition = this.buildHighlightPosition(diff.begin, diff.linenum, documentText);

           if (startPosition === undefined) {
               continue;
           }

           let endPosition = new vscode.Position(startPosition.line, startPosition.character + offset);

           let range = new vscode.Range(startPosition, endPosition);
           let highlight = new vscode.Diagnostic(range, diff.line_dest, vscode.DiagnosticSeverity.Error);

           allHighlights.push(highlight);
        }

        this.highlights.set(documentUri, allHighlights);
    };

    handleClear (suggestion) {
        this.highlights.clear();
    };

    // Kite's highlights provide positions that are absolutely indexed relative to the entire text.
    // Visual Studio's Diagnostic highlights expects the position to be relative to the line.
    buildHighlightPosition (position, linenum, text) {
        var remainingCharacters = position;
        let lines = text.split("\n");

        // Iterate until we get to the position of the character we need, and then build
        // a relative vscode.Position.
        for (var i = 0; i < lines.length; i++) {
            let charactersInLine = lines[i].length + 1; // +1 for the newline.

            if (remainingCharacters - charactersInLine < 0) {
                return new vscode.Position(linenum - 1, remainingCharacters)
            }

            remainingCharacters = remainingCharacters - charactersInLine;
        }

        // If we get here, there's probaly a buffer mismatch.
        return undefined;
    };

    validBuffer (suggestion) {
        const editor = vscode.window.activeTextEditor;

        if (!editor) {
            return false;
        }

        let text = editor.document.getText();
        let file_md5 = crypto.createHash("md5").update(text.toString()).digest("hex");
        let remote_md5 = suggestion.file_md5 || '';

        if (remote_md5 && remote_md5 !== file_md5) {
            console.log("buffer mismatch, remote:", remote_md5, "local:", file_md5);

            this.kiteOutgoing.sendError({
                "message": "buffer mismatch",
                "user_buffer": text.toString('base64'),
                "user_md5": file_md5,
                "expected_md5": remote_md5,
                "expected_buffer": suggestion.file_base64 || '',
                "suggestion": suggestion,
            });

            return false;
        }

        return true;
    };
};

// Listens for events from the editor and provides them to Kite.
var KiteEventController = class {
    constructor(incoming, outgoing) {
        this._incoming = incoming;
        this._outgoing = outgoing;

        // Incoming might need to send an error to Kite.
        incoming.kiteOutgoing = outgoing;

        let subscriptions = [];

        vscode.window.onDidChangeTextEditorSelection(this.onSelection, this, subscriptions);
        vscode.workspace.onDidChangeTextDocument(this.onEdit, this, subscriptions);
        vscode.window.onDidChangeActiveTextEditor(this.onEditorChange, this, subscriptions);

        this._disposable = vscode.Disposable.from(subscriptions);
    };

    dispose () {
        this._disposable.dispose();
    };

    // User selected some text.
    onSelection (event) {
        this._outgoing.onSelection(event);
    };

    // User edted some text.
    onEdit (event) {
        this._outgoing.onEdit(event);
    };

    // The text editor did change.
    onEditorChange (event) {
        this._outgoing.onEditorChange(event);
    };
};

exports.deactivate = deactivate;
exports.activate = activate;
exports.KiteOutgoing = KiteOutgoing;
exports.KiteIncoming = KiteIncoming;
exports.KiteEventController = KiteEventController;


text:
package com.microsoft.azure.management.compute.v2017_12_01;

import org.joda.time.DateTime;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
 * Api input base class for LogAnalytics Api.
 */
public class LogAnalyticsInputBase {
    /**
     * SAS Uri of the logging blob container to which LogAnalytics Api writes
     * output logs to.
     */
    @JsonProperty(value = "blobContainerSasUri", required = true)
    private String blobContainerSasUri;

    /**
     * From time of the query.
     */
    @JsonProperty(value = "fromTime", required = true)
    private DateTime fromTime;

    /**
     * To time of the query.
     */
    @JsonProperty(value = "toTime", required = true)
    private DateTime toTime;

    /**
     * Group query result by Throttle Policy applied.
     */
    @JsonProperty(value = "groupByThrottlePolicy")
    private Boolean groupByThrottlePolicy;

    /**
     * Group query result by  by Operation Name.
     */
    @JsonProperty(value = "groupByOperationName")
    private Boolean groupByOperationName;

    /**
     * Group query result by Resource Name.
     */
    @JsonProperty(value = "groupByResourceName")
    private Boolean groupByResourceName;

    /**
     * Get the blobContainerSasUri value.
     *
     * @return the blobContainerSasUri value
     */
    public String blobContainerSasUri() {
        return this.blobContainerSasUri;
    }

    /**
     * Set the blobContainerSasUri value.
     *
     * @param blobContainerSasUri the blobContainerSasUri value to set
     * @return the LogAnalyticsInputBase object itself.
     */
    public LogAnalyticsInputBase withBlobContainerSasUri(String blobContainerSasUri) {
        this.blobContainerSasUri = blobContainerSasUri;
        return this;
    }

    /**
     * Get the fromTime value.
     *
     * @return the fromTime value
     */
    public DateTime fromTime() {
        return this.fromTime;
    }

    /**
     * Set the fromTime value.
     *
     * @param fromTime the fromTime value to set
     * @return the LogAnalyticsInputBase object itself.
     */
    public LogAnalyticsInputBase withFromTime(DateTime fromTime) {
        this.fromTime = fromTime;
        return this;
    }

    /**
     * Get the toTime value.
     *
     * @return the toTime value
     */
    public DateTime toTime() {
        return this.toTime;
    }

    /**
     * Set the toTime value.
     *
     * @param toTime the toTime value to set
     * @return the LogAnalyticsInputBase object itself.
     */
    public LogAnalyticsInputBase withToTime(DateTime toTime) {
        this.toTime = toTime;
        return this;
    }

    /**
     * Get the groupByThrottlePolicy value.
     *
     * @return the groupByThrottlePolicy value
     */
    public Boolean groupByThrottlePolicy() {
        return this.groupByThrottlePolicy;
    }

    /**
     * Set the groupByThrottlePolicy value.
     *
     * @param groupByThrottlePolicy the groupByThrottlePolicy value to set
     * @return the LogAnalyticsInputBase object itself.
     */
    public LogAnalyticsInputBase withGroupByThrottlePolicy(Boolean groupByThrottlePolicy) {
        this.groupByThrottlePolicy = groupByThrottlePolicy;
        return this;
    }

    /**
     * Get the groupByOperationName value.
     *
     * @return the groupByOperationName value
     */
    public Boolean groupByOperationName() {
        return this.groupByOperationName;
    }

    /**
     * Set the groupByOperationName value.
     *
     * @param groupByOperationName the groupByOperationName value to set
     * @return the LogAnalyticsInputBase object itself.
     */
    public LogAnalyticsInputBase withGroupByOperationName(Boolean groupByOperationName) {
        this.groupByOperationName = groupByOperationName;
        return this;
    }

    /**
     * Get the groupByResourceName value.
     *
     * @return the groupByResourceName value
     */
    public Boolean groupByResourceName() {
        return this.groupByResourceName;
    }

    /**
     * Set the groupByResourceName value.
     *
     * @param groupByResourceName the groupByResourceName value to set
     * @return the LogAnalyticsInputBase object itself.
     */
    public LogAnalyticsInputBase withGroupByResourceName(Boolean groupByResourceName) {
        this.groupByResourceName = groupByResourceName;
        return this;
    }

}


text:
<?php

namespace Quintavalentina\Modules\Console\Generators;

class MakeModelCommand extends MakeCommand
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'make:module:model
    	{slug : The slug of the module.}
    	{name : The name of the model class.}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Create a new module model class';

    /**
     * String to store the command type.
     *
     * @var string
     */
    protected $type = 'Model';

    /**
     * Module folders to be created.
     *
     * @var array
     */
    protected $listFolders = [
        'Models/',
    ];

    /**
     * Module files to be created.
     *
     * @var array
     */
    protected $listFiles = [
        '{{filename}}.php',
    ];

    /**
     * Module stubs used to populate defined files.
     *
     * @var array
     */
    protected $listStubs = [
        'default' => [
            'model.stub',
        ],
    ];

    /**
     * Resolve Container after getting file path.
     *
     * @param string $filePath
     *
     * @return array
     */
    protected function resolveByPath($filePath)
    {
        $this->container['filename']  = $this->makeFileName($filePath);
        $this->container['namespace'] = $this->getNamespace($filePath);
        $this->container['path']      = $this->getBaseNamespace();
        $this->container['classname'] = basename($filePath);
    }

    /**
     * Replace placeholder text with correct values.
     *
     * @return string
     */
    protected function formatContent($content)
    {
        return str_replace(
            [
                '{{slug}}',
                '{{filename}}',
                '{{path}}',
                '{{namespace}}',
                '{{classname}}',
            ],
            [
                strtolower($this->argument('slug')),
                $this->container['filename'],
                $this->container['path'],
                $this->container['namespace'],
                $this->container['classname'],
            ],
            $content
        );
    }
}


text:
(function() {
	'use strict';

	angular
		.module('Startkicker.directives')
		.directive('fileModel', fileModel);

	fileModel.$inject = ['$parse', '$q'];

	function fileModel($parse, $q) {
		return {
			restrict: 'A',
			link: function(scope, element, attr) {
				var model = $parse(attr.fileModel);

				element.bind('change', function() {
					var files = Array.prototype.slice.call(element[0].files);

					$q.all(files.map(readFile))
						.then(function(data) {
							model.assign(scope.vm, data);
						});
				});

				function readFile(file) {
					var reader = new FileReader(),
						deferred = $q.defer();

					reader.onload = function(e) {
						var convertedFile = e.target.result;
						var result = {
							originalFileName: file.name.substr(0, file.name.lastIndexOf('.')),
							fileExtension: file.name.substr(file.name.lastIndexOf('.') + 1).toLowerCase(),
							base64Content: convertedFile.substr(convertedFile.indexOf(',') + 1)
						};

						deferred.resolve(result);
					};

					reader.onerror = function(e) {
						deferred.reject(e);
					};

					reader.readAsDataURL(file);

					return deferred.promise;
				}
			}
		};
	}
}());


text:
namespace _03.Dependency_Inversion
{
    using System;
    using _03DependencyInversion;

    public class StartUp
    {
        public static void Main()
        {
            StrategyManager manager = new StrategyManager();
            PrimitiveCalculator calculator = new PrimitiveCalculator(manager);

            var input = Console.ReadLine();

            while (input != "End")
            {
                var tokens = input.Split(' ');

                if (tokens[0] == "mode")
                {
                    var operatorr = char.Parse(tokens[1]);
                    calculator.ChangeStrategy(operatorr);
                }
                else
                {
                    var firstOperand = int.Parse(tokens[0]);
                    var secondOperand = int.Parse(tokens[1]);
                    Console.WriteLine(calculator.PerformCalculation(firstOperand, secondOperand));
                }

                input = Console.ReadLine();
            }
        }
    }
}


text:
namespace Decorator
{
    public abstract class Decorator : Vehicle
    {
        public Decorator(Vehicle vehicle)
        {
            this.Vehicle = vehicle;
        }

        protected Vehicle Vehicle { get; private set; }

        public override string Display()
        {
            return this.Vehicle.Display();
        }
    }
}


text:
namespace PokerTell.PokerHandParsers.FullTiltPoker
{
    /*
     * Full Tilt is not very consistent in indicating total Seats here some examples:

        CashGame
        	Headsup:
        	Full Tilt Poker Game #14861357336: Table Flash (heads up) - $0.25/$0.50 - No Limit Hold'em - 10:41:30 ET - 2009/09/22

        	6-max:
        	Full Tilt Poker Game #15705378958: Table Mascot (6 max) - $8/$16 - Limit Hold'em - 15:15:09 ET - 2009/10/31
        	Full Tilt Poker Game #15702319915: Table Chord (6 max) - $0.02/$0.05 - No Limit Hold'em - 12:26:53 ET - 2009/10/31

        	Full Tilt Poker Game #8455423700: Table Ash (deep 6) - $0.25/$0.50 - No Limit Hold'em - 9:13:55 ET - 2008/10/12

        	Full Tilt Poker Game #15568531231: Table Spur (6 max, deep) - $0.05/$0.10 - No Limit Hold'em - 8:21:39 ET - 2009/10/25

        Tournament
        	Headsup:
        	Full Tilt Poker Game #15311084867: $10 + $0.50 Heads Up Sit & Go (112266702), Table 1 - 20/40 - No Limit Hold'em - 11:33:59 ET - 2009/10/13

        	6-max:
        	Full Tilt Poker Game #20123762015: 250 Play Money Sit & Go (154480242), Table 1 - 15/30 - No Limit Hold'em - 15:55:40 ET - 2010/04/16

        	9-max
        	Full Tilt Poker Game #20098684607: 250 Play Money Sit & Go (154251582), Table 1 - 15/30 - No Limit Hold'em - 13:43:35 ET - 2010/04/15
     *
     *  the examples marked with a (*) are considered special cases for cash games
     *
     */

    using System;
    using System.Text.RegularExpressions;

    using PokerTell.PokerHandParsers.Interfaces.Parsers;

    public class TotalSeatsParser : Base.TotalSeatsParser, IFullTiltPokerTotalSeatsParser
    {
        readonly IFullTiltPokerPlayerSeatsParser _playerSeatsParser;

        const string SeatsMaxPattern = @"\((?<TotalSeats>\d{1,2}) max(, deep){0,1}\) ";

        const string DeepSeatsPattern = @"\(deep (?<TotalSeats>\d{1,2})\) ";

        const string CashGameSeatsPattern = SeatsMaxPattern + "|" + DeepSeatsPattern;
        const string FullTiltCashTableTotalSeatsPattern =
            TableNameParser.FullTiltCashTableNamePattern + CashGameSeatsPattern;

        const string HeadsUpPattern = TableNameParser.FullTiltCashTableNamePattern + @"\(heads up\) ";

        public bool IsTournament { get; set; }

        public int TotalSeatsRecord { get; set; }

        public TotalSeatsParser(IFullTiltPokerPlayerSeatsParser playerSeatsParser)
        {
            _playerSeatsParser = playerSeatsParser;
        }

        protected override string TotalSeatsPattern
        {
            get { return FullTiltCashTableTotalSeatsPattern; }
        }

        public override ITotalSeatsParser Parse(string handHistory)
        {
            IsValid = !string.IsNullOrEmpty(handHistory);
            if (IsValid)
                if (IsTournament)
                    ParseTournament(handHistory);
                else
                    ParseCashGame(handHistory);
            return this;
        }

        static Match MatchHeadsUp(string handHistory)
        {
            return Regex.Match(handHistory, HeadsUpPattern, RegexOptions.IgnoreCase);
        }

        void InCaseNoMatchWasFoundDefaultToNinePlayersSinceFullTiltDoesNotExplicitlyStateNinePlayerTables()
        {
            TotalSeats = 9;
        }

        void ParseCashGame(string handHistory)
        {
            Match totalSeats = MatchTotalSeats(handHistory);
            if (totalSeats.Success)
            {
                ExtractTotalSeats(totalSeats);
                return;
            }

            Match headsUp = MatchHeadsUp(handHistory);
            if (headsUp.Success)
            {
                TotalSeats = 2;
                return;
            }

            InCaseNoMatchWasFoundDefaultToNinePlayersSinceFullTiltDoesNotExplicitlyStateNinePlayerTables();
            return;
        }

        void ParseTournament(string handHistory)
        {
            if (_playerSeatsParser.Parse(handHistory).IsValid)
            {
                TotalSeats = TotalSeatsRecord < _playerSeatsParser.HighestSeatNumber
                    ? TotalSeatsMappedTo2Or6Or9(_playerSeatsParser.HighestSeatNumber)
                    : TotalSeatsRecord;
                IsValid = true;
            }
            else
            {
                IsValid = TotalSeatsRecord > 0;
                TotalSeats = TotalSeatsRecord;
            }

        }

        static int TotalSeatsMappedTo2Or6Or9(int highestSeatNumber)
        {
            if (highestSeatNumber > 6)
                return 9;
            return highestSeatNumber > 2 ? 6 : 2;
        }
    }
}


text:
package org.copperengine.core.persistent.hybrid;

import java.util.HashMap;
import java.util.Map;

/**
 * Internally used class.
 *
 * @author austermann
 */
final class TimeoutSlot {

    private final long timeoutTS;
    private final Map<String, Runnable> wfId2RunnableMap = new HashMap<>();

    public TimeoutSlot(long timeoutTS) {
        assert timeoutTS > 0;
        this.timeoutTS = timeoutTS;
    }

    public long getTimeoutTS() {
        return timeoutTS;
    }

    public Map<String, Runnable> getWfId2RunnableMap() {
        return wfId2RunnableMap;
    }
}


text:
import MySQLdb

class User(object):
    def __init__(self, user_id, username, passwd, age):
        self.user_id = user_id
        self.username = username
        self.passwd = passwd
        self.age = age

    def


text:
package com.mainmethod.premofm.object;

import com.mainmethod.premofm.data.model.FilterModel;
import com.mainmethod.premofm.helper.TextHelper;

import org.parceler.Parcel;

import java.util.Arrays;

/**
 * Created by evan on 6/14/15.
 */
@Parcel(Parcel.Serialization.BEAN)
public class Filter {

    private int mId;
    private String mName;
    private Integer[] mEpisodeStatusIds;
    private Integer[] mDownloadStatusIds;
    private boolean mFavorite;
    private int mCollectionId = FilterModel.DISABLED;
    private boolean mUserCreated;
    private int mFilterOrder;
    private int mEpisodesPerChannel = FilterModel.DISABLED;
    private int mDaysSincePublished = FilterModel.DISABLED;
    private boolean mEpisodesManuallyAdded;

    public Filter() {

    }

    public int getId() {
        return mId;
    }

    public void setId(int id) {
        mId = id;
    }

    public String getName() {
        return mName;
    }

    public void setName(String name) {
        mName = name;
    }

    public boolean isFavorite() {
        return mFavorite;
    }

    public void setFavorite(boolean favorite) {
        mFavorite = favorite;
    }

    public Integer[] getEpisodeStatusIds() {
        return mEpisodeStatusIds;
    }

    public String getEpisodeStatusIdsStr() {
        return TextHelper.joinIntegers(mEpisodeStatusIds);
    }

    public void setEpisodeStatusIds(Integer[] episodeStatusIds) {
        mEpisodeStatusIds = episodeStatusIds;
    }

    public void setEpisodeStatusIdsFromStr(String episodeStatusIdsStr) {
        mEpisodeStatusIds = TextHelper.splitToIntArray(episodeStatusIdsStr);
    }

    public Integer[] getDownloadStatusIds() {
        return mDownloadStatusIds;
    }

    public String getDownloadStatusIdsStr() {
        return TextHelper.joinIntegers(mDownloadStatusIds);
    }

    public void setDownloadStatusIds(Integer[] downloadStatusIds) {
        mDownloadStatusIds = downloadStatusIds;
    }

    public void setDownloadStatusIdsFromStr(String downloadStatusIdsStr) {
        mDownloadStatusIds = TextHelper.splitToIntArray(downloadStatusIdsStr);
    }

    public int getCollectionId() {
        return mCollectionId;
    }

    public void setCollectionId(int collectionId) {
        mCollectionId = collectionId;
    }

    public boolean isUserCreated() {
        return mUserCreated;
    }

    public void setUserCreated(boolean userCreated) {
        mUserCreated = userCreated;
    }

    public int getOrder() {
        return mFilterOrder;
    }

    public void setOrder(int order) {
        mFilterOrder = order;
    }

    public int getEpisodesPerChannel() {
        return mEpisodesPerChannel;
    }

    public void setEpisodesPerChannel(int episodesPerChannel) {
        mEpisodesPerChannel = episodesPerChannel;
    }

    public int getDaysSincePublished() {
        return mDaysSincePublished;
    }

    public void setDaysSincePublished(int daysSincePublished) {
        mDaysSincePublished = daysSincePublished;
    }

    public boolean isEpisodesManuallyAdded() {
        return mEpisodesManuallyAdded;
    }

    public void setEpisodesManuallyAdded(boolean episodesManuallyAdded) {
        mEpisodesManuallyAdded = episodesManuallyAdded;
    }

    @Override
    public int hashCode() {
        return mId;
    }

    @Override
    public String toString() {
        return "Filter{" +
                "mId=" + mId +
                ", mName='" + mName + '\'' +
                ", mEpisodeStatusIds=" + Arrays.toString(mEpisodeStatusIds) +
                ", mDownloadStatusIds=" + Arrays.toString(mDownloadStatusIds) +
                ", mFavorite=" + mFavorite +
                ", mCollectionId=" + mCollectionId +
                ", mUserCreated=" + mUserCreated +
                ", mFilterOrder=" + mFilterOrder +
                ", mEpisodesPerChannel=" + mEpisodesPerChannel +
                '}';
    }
}


text:
<!DOCTYPE html>

    <title>Design to Web</title>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.css">
    <link type="text/css" rel="stylesheet" href="../styles/main_v2.css">

From Design to Web.

Why is responsiveness important?

With the ever increasing variety of screen sizes that people use, websites need to be able to change their layout to fit accordingly. Otherwise content may not be presented properly to the user, and the user may have a bad experience - and means they may not come back.

What is mobile first design and why is it important?

Mobile first design refers to the practice of styling websites with mobile screens in mind first, and then adding further code for larger screens later. This means that small screen devices don't have to process a lot of extra code, which would slow them down.

Frameworks - pros & cons

Frameworks are blocks of pre-written CSS code that provide a lot of the structure to the layout. A pro is that it saves the developer a lot of time and makes layout much easier. A con is that sometimes the framework code overrides something the developer is trying to do. Also some frameworks may be unnecessarily large for the particular project.

Wireframes - why use them?

Wireframes are basic starting points for the design process. There is no style involved, just simply blocking out where every element will go and establishing heirachy of order etc. This is a quick and easy way to be able to visualise the webpage layout.

What aspects of wireframes did you find difficult to implement?

I found that the design of my webpage became more unlike my wireframe as time went on.

The most challenging thing for me has been the mobile first design - and I still haven't got it down yet. Writing html for a large screen, in terms of rows and columns, but then styling it for a small screen was difficult to get my head around

Previous

Next

Cultural

Home