From 67eea2b65111bb2ab0dbe06d2c0d2b002a875b0d Mon Sep 17 00:00:00 2001 From: Lwangaman Date: Fri, 27 Mar 2020 18:16:06 +0000 Subject: [PATCH] publish new tag 5.0 to wordpress plugins --- bibleget-io.php | 248 ++++++------- css/admin.css | 39 +- css/popup.css | 7 +- custom_controls.php | 32 +- js/admin.js | 347 ++++++++++++++---- js/he.js | 91 ++--- js/jquery.fontselect.js | 69 +++- js/shortcode.js | 6 +- js/theme-customizer.js | 17 +- options.php | 785 +++++++++++++++++++++++++++++++--------- readme.txt | 40 +- 11 files changed, 1240 insertions(+), 441 deletions(-) diff --git a/bibleget-io.php b/bibleget-io.php index 3335d98..8a0cba1 100644 --- a/bibleget-io.php +++ b/bibleget-io.php @@ -1,17 +1,17 @@ "Matthew1:1-5", @@ -149,9 +149,9 @@ function bibleget_shortcode($atts = [], $content = null, $tag = '') { 'forcecopyright'=> false, 'popup' => false ), $atts, $tag ); - + // echo "
".$a["query"]."
"; - + // Determine bible version(s) $versions = array (); if ($a ["versions"] !== "") { @@ -162,13 +162,13 @@ function bibleget_shortcode($atts = [], $content = null, $tag = '') { } else { $versions = explode ( ",", $a ["version"] ); } - + if (count ( $versions ) < 1) { /* translators: do NOT translate the parameter names "version" or "versions" !!! */ $output = '' . __ ( 'You must indicate the desired version with the parameter "version" (or the desired versions as a comma separated list with the parameter "versions")', "bibleget-io" ) . ''; return '
' . $output . '
'; } - + $vversions = get_option ( "bibleget_versions", array () ); if (count ( $vversions ) < 1) { bibleGetSetOptions (); @@ -186,14 +186,14 @@ function bibleget_shortcode($atts = [], $content = null, $tag = '') { } } } - + if($content !== null && $content != ""){ $queries = bibleGetQueryClean ( $content ); } else{ $queries = bibleGetQueryClean ( $a ['query'] ); } - + if (is_array ( $queries )) { $goodqueries = bibleGetProcessQueries ( $queries, $versions ); // bibleGetWriteLog("value of goodqueries after bibleGetProcessQueries:"); @@ -202,7 +202,7 @@ function bibleget_shortcode($atts = [], $content = null, $tag = '') { $output = __ ( "BibleGet Bible Quote placeholder... (error processing query, please check syntax)", "bibleget-io" ); return '
' . $output . '
'; } - + $finalquery = "query="; $finalquery .= implode ( ";", $goodqueries ); $finalquery .= "&version="; @@ -215,7 +215,7 @@ function bibleget_shortcode($atts = [], $content = null, $tag = '') { } // bibleGetWriteLog("value of finalquery = ".$finalquery); if ($finalquery != "") { - + if (false === ($output = get_transient ( md5 ( $finalquery ) ))) { // $output = $finalquery; // return '
' . $output . '
'; @@ -227,10 +227,10 @@ function bibleget_shortcode($atts = [], $content = null, $tag = '') { $output = '' . __ ( "BibleGet Bible Quote placeholder... (temporary error from the BibleGet server. Please try again in a few minutes...)", "bibleget-io" ) . ''; } } - + wp_enqueue_script ( 'bibleget-script', plugins_url ( 'js/shortcode.js', __FILE__ ), array ( 'jquery' ), '1.0', true ); wp_enqueue_script ( 'htmlentities-script', plugins_url ( 'js/he.min.js', __FILE__ ), array ( 'jquery' ), '1.0', true ); - + if($a ['popup'] == "true"){ wp_enqueue_script ( 'jquery-ui-dialog' ); wp_enqueue_style ( 'wp-jquery-ui-dialog' ); @@ -262,34 +262,34 @@ function bibleget_shortcode($atts = [], $content = null, $tag = '') { /** - * BibleGet Query Server Function + * BibleGet Query Server Function * @param unknown $finalquery * After a query has been checked for integrity, this will send the query request to the BibleGet Server * Returns the response from the BibleGet Server */ function bibleGetQueryServer($finalquery) { $errs = array(); - //We will make a secure connection to the BibleGet service endpoint, - //if this server's OpenSSL and CURL versions support TLSv1.2 - $version = curl_version(); - $ssl_version = str_replace('OpenSSL/','',$version['ssl_version']); - if( version_compare( $version['version'], '7.34.0', '>=') && version_compare( $ssl_version, '1.0.1', '>=' ) ){ + //We will make a secure connection to the BibleGet service endpoint, + //if this server's OpenSSL and CURL versions support TLSv1.2 + $curl_version = curl_version(); + $ssl_version = str_replace('OpenSSL/','',$curl_version['ssl_version']); + if( version_compare( $curl_version['version'], '7.34.0', '>=') && version_compare( $ssl_version, '1.0.1', '>=' ) ){ //we should be good to go for secure SSL communication supporting TLSv1_2 $ch = curl_init ( "https://query.bibleget.io/index.php?" . $finalquery . "&return=html&appid=wordpress&domain=" . urlencode ( site_url () ) . "&pluginversion=" . BIBLEGETPLUGINVERSION ); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2 ); //echo "
" . plugins_url ( 'DST_Root_CA.cer',__FILE__ ) . "
"; //curl_setopt($ch, CURLOPT_CAINFO, plugin_dir_path ( __FILE__ ) . "DST_Root_CA.cer"); //seems to work.. ??? //curl_setopt($ch, CURLOPT_CAINFO, plugin_dir_path ( __FILE__ ) . "DST_Root_CA.pem"); - + } else{ $ch = curl_init ( "http://query.bibleget.io/index.php?" . $finalquery . "&return=html&appid=wordpress&domain=" . urlencode ( site_url () ) . "&pluginversion=" . BIBLEGETPLUGINVERSION ); } - + curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, TRUE ); - + if (ini_get ( 'safe_mode' ) || ini_get ( 'open_basedir' )) { // safe mode is on, we can't use some settings } else { @@ -301,13 +301,13 @@ function bibleGetQueryServer($finalquery) { // remove style and title tags from the output if they are present(should not be present with more recent BibleGet engine $output = substr ( $output, 0, strpos ( $output, "', $output, - 1, $count1 ); $output = preg_replace ( '/<\/(sm|pof|po|pol|pos|poif|poi|poil|po3|po3l|speaker)>/', '', $output, - 1, $count2 ); // $output .= "

Effettuate ".$count1." e ".$count2." sostituzioni."; - + $matches = null; if (preg_match_all ( "/
.*?<\/div>/s", $output, $matches )) { // capture table of error messages, and turn it into notices for backend @@ -328,9 +328,9 @@ function bibleGetQueryServer($finalquery) { $output = false; } curl_close ( $ch ); - + update_option ( 'bibleget_error_admin_notices', $errs ); - + return $output; } @@ -345,7 +345,7 @@ function bibleGetQueryServer($finalquery) { function bibleGetProcessQueries($queries, $versions) { $goodqueries = array (); - + $thisbook = null; if (get_option ( "bibleget_" . $versions [0] . "IDX" ) === false) { bibleGetSetOptions (); @@ -382,9 +382,9 @@ function bibleGetProcessQueries($queries, $versions) { } // bibleGetWriteLog("indexes array should now be populated:"); // bibleGetWriteLog($indexes); - + $notices = get_option ( 'bibleget_error_admin_notices', array () ); - + foreach ( $queries as $key => $value ) { $thisquery = bibleGetToProperCase ( $value ); // shouldn't be necessary because already array_mapped, but better safe than sorry if ($key === 0) { @@ -400,8 +400,8 @@ function bibleGetProcessQueries($queries, $versions) { //TODO: why are we returning $thisbook if we don't even use it here? array_push ( $goodqueries, $thisquery ); } else { - return $thisbook; - //TODO: double check if this really needs to return false here? + return $thisbook; + //TODO: double check if this really needs to return false here? //Does this prevent it from continuing integrity checks with the rest of the queries? //Shouldn't it just be "continue;"? } @@ -415,7 +415,7 @@ function bibleGetProcessQueries($queries, $versions) { * @param unknown $thisquery * @param unknown $indexes * @param string $thisbook - * + * * Performs complex integrity checks on the queries * Gives feedback on the malformed queries to help the user get their query right * Returns false if the query is not healthy enough to send to the BibleGet Server @@ -441,10 +441,10 @@ function bibleGetCheckQuery($thisquery, $indexes, $thisbook = "") { /* translators: the expressions %1$d, %2$d, and %3$s must be left as is, they will be substituted dynamically by values in the script. See http://php.net/sprintf. */ $errorMessages [9] = __ ( 'The values concatenated by the dot must be consecutive, instead %1$d >= %2$d in the expression <%3$s>', "bibleget-io" ); $errorMessages [10] = __ ( "A query that doesn't start with a book indicator must however start with a valid chapter indicator!", "bibleget-io" ); - + $errs = get_option ( 'bibleget_error_admin_notices', array () ); $dummy = array (); // to avoid error messages on systems with PHP < 5.4 which required third parameter in preg_match_all - + if (preg_match ( "/^([1-3]{0,1}((\p{L}\p{M}*)+))/", $thisquery, $res )) { $thisbook = $res [0]; if (! preg_match ( "/^[1-3]{0,1}((\p{L}\p{M}*)+)[1-9][0-9]{0,2}/", $thisquery ) || preg_match_all ( "/^[1-3]{0,1}((\p{L}\p{M}*)+)/", $thisquery, $dummy ) != preg_match_all ( "/^[1-3]{0,1}((\p{L}\p{M}*)+)[1-9][0-9]{0,2}/", $thisquery, $dummy )) { @@ -452,11 +452,11 @@ function bibleGetCheckQuery($thisquery, $indexes, $thisbook = "") { update_option ( 'bibleget_error_admin_notices', $errs ); return false; } - + $validBookIndex = ( int ) bibleGetIsValidBook ( $thisbook ); if ($validBookIndex != - 1) { $thisquery = str_replace ( $thisbook, "", $thisquery ); - + if (strpos ( $thisquery, "." )) { if (! strpos ( $thisquery, "," ) || strpos ( $thisquery, "," ) > strpos ( $thisquery, "." )) { // error message: You cannot use a dot without first using a comma. A dot is a liason between verses, which are separated from the chapter by a comma. @@ -469,7 +469,7 @@ function bibleGetCheckQuery($thisquery, $indexes, $thisbook = "") { update_option ( 'bibleget_error_admin_notices', $errs ); return false; } - + // if(preg_match_all("/(?=[1-9][0-9]{0,2}\.[1-9][0-9]{0,2})/",$query) != substr_count($query,".") ){ // if(preg_match_all("/(?=([1-9][0-9]{0,2}\.[1-9][0-9]{0,2}))/",$query) < substr_count($query,".") ){ if (preg_match_all ( "/(? 1) { @@ -566,7 +566,7 @@ function bibleGetCheckQuery($thisquery, $indexes, $thisbook = "") { if (preg_match_all ( "/[,\.][1-9][0-9]{0,2}\-([1-9][0-9]{0,2})/", $thisquery, $matches )) { if (! is_array ( $matches [1] )) { $matches [1] = array ( - $matches [1] + $matches [1] ); } $highverse = intval ( array_pop ( $matches [1] ) ); @@ -604,11 +604,11 @@ function bibleGetCheckQuery($thisquery, $indexes, $thisbook = "") { } } } - + if (preg_match_all ( "/\.([1-9][0-9]{0,2})$/", $thisquery, $matches )) { if (! is_array ( $matches [1] )) { $matches [1] = array ( - $matches [1] + $matches [1] ); } $highverse = array_pop ( $matches [1] ); @@ -645,7 +645,7 @@ function bibleGetCheckQuery($thisquery, $indexes, $thisbook = "") { } } } - + if (strpos ( $thisquery, "-" )) { if (preg_match_all ( "/[1-9][0-9]{0,2}\-[1-9][0-9]{0,2}/", $thisquery, $dummy ) != substr_count ( $thisquery, "-" )) { // error message: A dash must be preceded and followed by 1 to 3 digits etc. @@ -667,7 +667,7 @@ function bibleGetCheckQuery($thisquery, $indexes, $thisbook = "") { update_option ( 'bibleget_error_admin_notices', $errs ); return false; } - + // if there's a comma before if (preg_match ( "/([1-9][0-9]{0,2}\,[1-9][0-9]{0,2}\-[1-9][0-9]{0,2})/", $thisquery, $matchA )) { // if there's a comma after, we're dealing with chapter,verse to chapter,verse @@ -735,8 +735,8 @@ function bibleGetCheckQuery($thisquery, $indexes, $thisbook = "") { /** * BibleGet To ProperCase * @param unknown $txt - * - * Helper function that modifies the query so that it is in a correct Proper Case, + * + * Helper function that modifies the query so that it is in a correct Proper Case, * taking into account numbers at the beginning of the string * Can handle any kind of Unicode string in any language */ @@ -760,7 +760,7 @@ function bibleGetToProperCase($txt) { * BibleGet IndexOf Function * @param unknown $needle * @param unknown $haystack - * + * * Helper function that will return the index of a bible book from a two-dimensional index array */ function bibleGetIdxOf($needle, $haystack) { @@ -804,10 +804,10 @@ function bibleGetIsValidBook($book) { function bibleGetGetMetaData($request) { // request can be for building the biblebooks variable, or for building version indexes, or for requesting current validversions $notices = get_option ( 'bibleget_error_admin_notices', array () ); - - $version = curl_version(); - $ssl_version = str_replace('OpenSSL/','',$version['ssl_version']); - if( version_compare( $version['version'], '7.34.0', '>=') && version_compare( $ssl_version, '1.0.1', '>=' ) ){ + + $curl_version = curl_version(); + $ssl_version = str_replace('OpenSSL/','',$curl_version['ssl_version']); + if( version_compare( $curl_version['version'], '7.34.0', '>=') && version_compare( $ssl_version, '1.0.1', '>=' ) ){ //we should be good to go for secure SSL communication supporting TLSv1_2 $url = "https://query.bibleget.io/metadata.php?query=" . $request . "&return=json"; $ch = curl_init ( $url ); @@ -817,22 +817,22 @@ function bibleGetGetMetaData($request) { //echo "
" . plugins_url ( 'DST_Root_CA.cer',__FILE__ ) . "
"; //curl_setopt($ch, CURLOPT_CAINFO, plugin_dir_path ( __FILE__ ) . "ca/DST_Root_CA.cer"); //seems to work.. ??? //curl_setopt($ch, CURLOPT_CAINFO, plugin_dir_path ( __FILE__ ) . "DST_Root_CA.pem"); - + } else{ $url = "http://query.bibleget.io/metadata.php?query=" . $request . "&return=json"; $ch = curl_init ( $url ); } - + curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, TRUE ); - + if (ini_get ( 'safe_mode' ) || ini_get ( 'open_basedir' )) { // safe mode is on, we can't use some settings } else { curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, TRUE ); curl_setopt ( $ch, CURLOPT_AUTOREFERER, TRUE ); } - + $response = curl_exec ( $ch ); if (curl_errno ( $ch ) && (curl_errno($ch) === 77 || curl_errno($ch) === 60) && $url == "https://query.bibleget.io/metadata.php?query=" . $request . "&return=json" ) { //error 60: SSL certificate problem: unable to get local issuer certificate @@ -880,7 +880,7 @@ function bibleGetGetMetaData($request) { } } curl_close ( $ch ); - + $myjson = json_decode ( $response ); if (property_exists ( $myjson, "results" )) { return $myjson; @@ -896,7 +896,7 @@ function bibleGetGetMetaData($request) { /** - * + * * @param unknown $query * @return number */ @@ -908,7 +908,7 @@ function bibleGetQueryClean($query) { $query = trim ( $query ); $query = preg_replace ( '/\s+/', '', $query ); $query = str_replace ( ' ', '', $query ); - + if (strpos ( $query, ':' ) && strpos ( $query, '.' )) { return __ ( "Mixed notations have been detected. Please use either english notation or european notation.", "bibleget-io" ) . '<' + $query + '>'; } else if (strpos ( $query, ':' )) { // if english notation is detected, translate it to european notation @@ -920,13 +920,13 @@ function bibleGetQueryClean($query) { $queries = array_values ( array_filter ( explode ( ';', $query ), function ($var) { return $var !== ""; } ) ); - + return array_map ( "bibleGetToProperCase", $queries ); } /** - * + * */ function bibleget_admin_notices() { if ($notices = get_option ( 'bibleget_error_admin_notices' )) { @@ -946,32 +946,32 @@ function bibleget_admin_notices() { /** - * + * */ function bibleGetDeleteOptions() { // DELETE BIBLEGET_BIBLEBOOKS CACHED INFO for($i = 0; $i < 73; $i ++) { delete_option ( "bibleget_biblebooks" . $i ); } - + // DELETE BIBLEGET_LANGUAGES CACHED INFO delete_option ( "bibleget_languages" ); - + // DELETE BIBLEGET_VERSIONS CACHED INFO $bibleversions = json_decode ( get_option ( "bibleget_versions" ) ); delete_option ( "bibleget_versions" ); - + // DELETE BIBLEGET_VERSIONINDEX CACHED INFO $bibleversionsabbrev = get_object_vars ( $bibleversions ); foreach ( $bibleversionsabbrev as $abbrev ) { delete_option ( "bibleget_" . $abbrev . "IDX" ); } - + } /** - * + * */ function bibleGetSetOptions() { $metadata = bibleGetGetMetaData ( "biblebooks" ); @@ -994,7 +994,7 @@ function bibleGetSetOptions() { update_option ( "bibleget_languages", $languages ); } } - + $metadata = bibleGetGetMetaData ( "bibleversions" ); $versionsabbrev = array (); if ($metadata !== false) { @@ -1010,7 +1010,7 @@ function bibleGetSetOptions() { // bibleGetWriteLog("versionsabbrev should now be populated:"); // bibleGetWriteLog($versionsabbrev); } - + if (count ( $versionsabbrev ) > 0) { $versionsstr = implode ( ',', $versionsabbrev ); $metadata = bibleGetGetMetaData ( "versionindex&versions=" . $versionsstr ); @@ -1031,7 +1031,7 @@ function bibleGetSetOptions() { } } } - + // we only want the script to die if it's an ajax request... if (isset ( $_POST ["isajax"] ) && $_POST ["isajax"] == 1) { $notices = get_option ( 'bibleget_admin_notices', array () ); @@ -1166,7 +1166,7 @@ function bibleGetSetOptions() { "xh" => "Xhosa", "yi" => "Yiddish", "yo" => "Yoruba", - "zu" => "Zulu" + "zu" => "Zulu" ); $bibleget_worldlanguages = array ( @@ -1175,173 +1175,173 @@ function bibleGetSetOptions() { "it" => "Afrikaans", "es" => "Afrikáans", "fr" => "Afrikaans", - "de" => "Afrikaans" + "de" => "Afrikaans" ), "Albanian" => array ( "en" => "Albanian", "it" => "Albanese", "es" => "Albanés", "fr" => "Albanais", - "de" => "Albanisch" + "de" => "Albanisch" ), "Arabic" => array ( "en" => "Arabic", "it" => "Arabo", "es" => "Árabe", "fr" => "Arabe", - "de" => "Arabisch" + "de" => "Arabisch" ), "Chinese" => array ( "en" => "Chinese", "it" => "Cinese", "es" => "Chino", "fr" => "Chinois", - "de" => "Chinesische" + "de" => "Chinesische" ), "Croatian" => array ( "en" => "Croatian", "it" => "Croato", "es" => "Croata", "fr" => "Croate", - "de" => "Kroatisch" + "de" => "Kroatisch" ), "Czech" => array ( "en" => "Czech", "it" => "Ceco", "es" => "Checo", "fr" => "Tchèque", - "de" => "Tschechisch" + "de" => "Tschechisch" ), "English" => array ( "en" => "English", "it" => "Inglese", "es" => "Inglés", "fr" => "Anglais", - "de" => "Englisch" + "de" => "Englisch" ), "French" => array ( "en" => "French", "it" => "Francese", "es" => "Francés", "fr" => "Français", - "de" => "Französisch" + "de" => "Französisch" ), "German" => array ( "en" => "German", "it" => "Tedesco", "es" => "Alemán", "fr" => "Allemand", - "de" => "Deutsch" + "de" => "Deutsch" ), "Greek" => array ( "en" => "Greek", "it" => "Greco", "es" => "Griego", "fr" => "Grec", - "de" => "Griechisch" + "de" => "Griechisch" ), "Hungarian" => array ( "en" => "Hungarian", "it" => "Ungherese", "es" => "Húngaro", "fr" => "Hongrois", - "de" => "Ungarisch" + "de" => "Ungarisch" ), "Italian" => array ( "en" => "Italian", "it" => "Italiano", "es" => "Italiano", "fr" => "Italien", - "de" => "Italienisch" + "de" => "Italienisch" ), "Japanese" => array ( "en" => "Japanese", "it" => "Giapponese", "es" => "Japonés", "fr" => "Japonais", - "de" => "Japanisch" + "de" => "Japanisch" ), "Korean" => array ( "en" => "Korean", "it" => "Coreano", "es" => "Coreano", "fr" => "Coréen", - "de" => "Koreanisch" + "de" => "Koreanisch" ), "Latin" => array ( "en" => "Latin", "it" => "Latino", "es" => "Latín", "fr" => "Latin", - "de" => "Lateinisch" + "de" => "Lateinisch" ), "Polish" => array ( "en" => "Polish", "it" => "Polacco", "es" => "Polaco", "fr" => "Polonais", - "de" => "Russisch" + "de" => "Russisch" ), "Portuguese" => array ( "en" => "Portuguese", "it" => "Portoghese", "es" => "Portugués", "fr" => "Portugais", - "de" => "Portugiesisch" + "de" => "Portugiesisch" ), "Romanian" => array ( "en" => "Romanian", "it" => "Rumeno", "es" => "Rumano", "fr" => "Roumain", - "de" => "Rumänischen" + "de" => "Rumänischen" ), "Russian" => array ( "en" => "Russian", "it" => "Russo", "es" => "Ruso", "fr" => "Russe", - "de" => "Russisch" + "de" => "Russisch" ), "Spanish" => array ( "en" => "Spanish", "it" => "Spagnolo", "es" => "Español", "fr" => "Espagnol", - "de" => "Spanisch" + "de" => "Spanisch" ), "Tagalog" => array ( "en" => "Tagalog", "it" => "Tagalog", "es" => "Tagalo", "fr" => "Tagalog", - "de" => "Tagalog" + "de" => "Tagalog" ), "Tamil" => array ( "en" => "Tamil", "it" => "Tamil", "es" => "Tamil", "fr" => "Tamoul", - "de" => "Tamilisch" + "de" => "Tamilisch" ), "Thai" => array ( "en" => "Thai", "it" => "Thai", "es" => "Thai", "fr" => "Thaï", - "de" => "Thailändisch" + "de" => "Thailändisch" ), "Vietnamese" => array ( "en" => "Vietnamese", "it" => "Vietnamita", "es" => "Vietnamita", "fr" => "Vietnamien", - "de" => "Vietnamesisch" - ) + "de" => "Vietnamesisch" + ) ); /** - * + * * @param unknown $string */ function bibleGetSortify($string) { @@ -1358,7 +1358,7 @@ function bibleGetSortify($string) { /** * END OF SETTINGS PAGE - * + * * START OF CUSTOMIZER OPTIONS */ @@ -1370,25 +1370,25 @@ function bibleGetSortify($string) { // Setup the Theme Customizer settings and controls... add_action ( 'customize_register', array ( 'BibleGet_Customize', - 'register' + 'register' ) ); // Output custom CSS to live site add_action ( 'wp_head', array ( 'BibleGet_Customize', - 'header_output' + 'header_output' ) ); // Enqueue live preview javascript in Theme Customizer admin screen add_action ( 'customize_preview_init', array ( 'BibleGet_Customize', - 'live_preview' + 'live_preview' ) ); /** * Function bibleGetWriteLog * useful for debugging purposes - * + * * @param unknown $log */ function bibleGetWriteLog($log) { @@ -1414,26 +1414,26 @@ function bibleGetWriteLog($log) { add_filter ( 'plugin_action_links_' . plugin_basename ( __FILE__ ), 'bibleGetAddActionLinks' ); /** - * + * * @param unknown $links */ function bibleGetAddActionLinks($links) { $mylinks = array ( - '' . __ ( 'Settings' ) . '' + '' . __ ( 'Settings' ) . '' ); return array_merge ( $links, $mylinks ); } /** - * + * * @param unknown $parentNode * @param unknown $tagName * @param unknown $className */ function bibleGetGetElementsByClass(&$parentNode, $tagName, $className) { $nodes = array (); - + $childNodeList = $parentNode->getElementsByTagName ( $tagName ); for($i = 0; $i < $childNodeList->length; $i ++) { $temp = $childNodeList->item ( $i ); @@ -1441,13 +1441,13 @@ function bibleGetGetElementsByClass(&$parentNode, $tagName, $className) { $nodes [] = $temp; } } - + return $nodes; } /** - * + * */ function bibleGetCurrentPageUrl() { $pageURL = 'http'; diff --git a/css/admin.css b/css/admin.css index 605e8e8..289653f 100644 --- a/css/admin.css +++ b/css/admin.css @@ -124,4 +124,41 @@ form input[type=color] { color: white; text-decoration: none; font-weight: bold; -} \ No newline at end of file +} + +#gfontsBatchRunProgressBarOverlay { + background-color: black; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + opacity: 0.5; /* also -moz-opacity, etc. */ +} + +#gfontsBatchRunProgressBarWrapper { + position: fixed; + top: 50%; + width: 100%; +} + +#gfontsBatchRunProgressbar{ + position:relative; + width: 50%; + margin: 0px auto; +} + +#gfontsBatchRunProgressbarLabelWrapper { + position: absolute; + top: 5px; + width: 100%; + text-align: center; +} + +#gfontsBatchRunProgressbarLabel { + position: relative; + color:#000; + font-weight: bold; + top: 4px; + margin: 0px auto; +} diff --git a/css/popup.css b/css/popup.css index a88cfbc..4a3c6af 100644 --- a/css/popup.css +++ b/css/popup.css @@ -11,8 +11,7 @@ height: auto; } + .ui-dialog .ui-dialog-titlebar-close { - height: 30px; - padding: 0px; - margin: -20px 0 0 0; -} \ No newline at end of file + background-color: transparent !important; +} diff --git a/custom_controls.php b/custom_controls.php index 181bd9b..03f067b 100644 --- a/custom_controls.php +++ b/custom_controls.php @@ -59,15 +59,15 @@ class BibleGet_Customize_FontSelect_Control extends WP_Customize_Control { public function __construct($manager, $id, $args = array() ){ parent::__construct( $manager, $id, $args ); } - + */ public function enqueue() { - + wp_enqueue_script ( 'bibleget-fontselect-library', // Give the script a unique ID plugins_url ( 'js/jquery.fontselect.js', __FILE__ ), // Define the path to the JS file array ( 'jquery' ), // Define dependencies '', // Define a version (optional) - true ); // Specify whether to put in footer (leave this true) + true ); // Specify whether to put in footer (leave this true) wp_enqueue_script ( 'bibleget-fontselect-control', // Give the script a unique ID plugins_url ( 'js/fontselect-control.js', __FILE__ ), // Define the path to the JS file array ( 'bibleget-fontselect-library' ), // Define dependencies @@ -76,7 +76,25 @@ public function enqueue() { wp_enqueue_style ( 'bibleget-fontselect-control-style', plugins_url ( 'css/fontselect.css', __FILE__ ) // Define the path to the CSS file ); - + + if( file_exists( plugin_dir_path( __FILE__ ) . 'css/gfonts_preview/gfonts_preview.css' ) ){ + wp_enqueue_style( 'bibleget-fontselect-preview', + plugins_url ('css/gfonts_preview/gfonts_preview.css', __FILE__ ) + ); + } + else{ + echo ''; + } + + //I'm guessing this is where we do our background checks on the Google Fonts API key? + $bibleget_settings = get_option( 'bibleget_settings' ); + if(isset( $bibleget_settings['googlefontsapi_key'] ) && $bibleget_settings['googlefontsapi_key'] != ""){ + if(get_transient ( md5 ( $bibleget_settings['googlefontsapi_key'] ) ) == "SUCCESS"){ + //We have a google fonts key that has been tested successfully in the past 3 months + wp_localize_script('bibleget-fontselect-library','FontSelect_Control',array('bibleget_settings' => $bibleget_settings,'pluginUrl' => plugins_url("", __FILE__ ))); + } + } + } public function render_content() { @@ -85,10 +103,10 @@ public function render_content() { description )) : ?> description ); ?> - link(); ?> type="hidden" value="value(); ?>" /> + link(); ?> type="hidden" data-fonttype="websafe" value="value(); ?>" /> -3 secs...') - .fadeIn("slow", function() { - var seconds = 3; - interval1 = setInterval(function() { - jQuery("#bibleget-countdown").text( - --seconds - + (seconds==1?" sec...":" secs...")); - }, 1000); - var timeout1 = setTimeout(function() { - clearInterval(interval1); - location.reload(true); - }, 3000); - }); - } else { - jQuery("#bibleget-settings-notification").append( - 'Communication with the server seems to have been successful, however it does not seem that we have received the refreshed data... Perhaps try again?') - .fadeIn("slow"); - } - jQuery(".bibleget-settings-notification-dismiss") - .click(function() { - jQuery("#bibleget-settings-notification").fadeOut("slow"); - }); - }, - error : function(xhr, ajaxOptions, thrownError) { - jQuery("#bibleget-settings-notification") - .fadeIn("slow") - .append('Communication with the BibleGet server was not successfull... ERROR: ' + xhr.responseText); - jQuery(".bibleget-settings-notification-dismiss") - .click(function() { - jQuery("#bibleget-settings-notification").fadeOut("slow"); - }); + // check again how to do wordpress ajax, + // really no need to do a makeshift ajax + // post to this page + postdata = { + action : 'refresh_bibleget_server_data', + security : bibleGetOptionsFromServer.ajax_nonce, + isajax : 1 + }; + var interval1 = null; + jQuery.ajax({ + type : 'POST', + url : bibleGetOptionsFromServer.ajax_url, + data : postdata, + beforeSend : function() { + jQuery('#bibleget_ajax_spinner').show(); + }, + complete : function() { + jQuery('#bibleget_ajax_spinner').hide(); + }, + success : function(returndata) { + if (returndata == 'datarefreshed') { + jQuery( + "#bibleget-settings-notification") + .append( + 'Data from server retrieved successfully, now refreshing page... 3 secs...') + .fadeIn("slow", function() { + var seconds = 3; + interval1 = setInterval(function() { + jQuery("#bibleget-countdown").text( + --seconds + + (seconds==1?" sec...":" secs...")); + }, 1000); + var timeout1 = setTimeout(function() { + clearInterval(interval1); + location.reload(true); + }, 3000); + }); + } else { + jQuery("#bibleget-settings-notification").append( + 'Communication with the server seems to have been successful, however it does not seem that we have received the refreshed data... Perhaps try again?') + .fadeIn("slow"); + } + jQuery(".bibleget-settings-notification-dismiss") + .click(function() { + jQuery("#bibleget-settings-notification").fadeOut("slow"); + }); + }, + error : function(xhr, ajaxOptions, thrownError) { + jQuery("#bibleget-settings-notification") + .fadeIn("slow") + .append('Communication with the BibleGet server was not successful... ERROR: ' + xhr.responseText); + jQuery(".bibleget-settings-notification-dismiss") + .click(function() { + jQuery("#bibleget-settings-notification").fadeOut("slow"); + }); - } - }); - }); + } + }); + }); + + if(typeof gfontsBatch !== 'undefined' && typeof gfontsBatch === 'object' && gfontsBatch.hasOwnProperty('job') && gfontsBatch.job.hasOwnProperty('gfontsPreviewJob') && gfontsBatch.job.gfontsPreviewJob === true && gfontsBatch.job.hasOwnProperty('gfontsWeblist') && typeof gfontsBatch.job.gfontsWeblist == 'object' && gfontsBatch.job.gfontsWeblist.hasOwnProperty('items') ){ + console.log('We have a gfontsPreviewJob to do! gfontsBatch: '); + console.log(gfontsBatch); + + var startIdx = 0; //starting index for this batch run + var gfontsCount = gfontsBatch.job.gfontsWeblist.items.length; + var batchLimit = 300; //general batch limit for each run, so that we don't block the server but yet we try to do a good number if we can + var lastBatchLimit = 0; //if we have a remainder from the full batches, this will be the batchLimit for that remainder + var numRuns = 0; //we'll set this in a minute + var currentRun = 1; //of course we start from 1, the first run + + //Let's calculate how many times we will have to make the ajax call + // in order to complete the local download of all the requested miniaturized font files + //Perhaps lastBatchLimit variable is superfluous because PHP will check bounds, + // but hey let's be precise on each side, why not + if(gfontsCount % batchLimit == 0){ + numRuns = (gfontsCount / batchLimit); + console.log('gfontsCount is divided evenly by the batchLimit, numRuns should be an integer such as 3. numRuns = '+numRuns); + } + else if((gfontsCount % batchLimit) > 0){ + numRuns = Math.floor(gfontsCount / batchLimit) + 1; + lastBatchLimit = (gfontsCount % batchLimit); + console.log('gfontsCount is not divided evenly by the batchLimit, we have a remainder. numRuns should be an integer larger by one compared to the value of that division, 4 in this case. numRuns = '+numRuns); + console.log('gfontsCount = '+gfontsCount); + console.log('batchLimit = '+batchLimit); + } + + //$gfontsBatchRunProgressbarOverlay, $gfontsBatchRunProgressbarWrapper, and $gfontsBatchRunProgressbar are global variables so don't use "var" here + $gfontsBatchRunProgressbarOverlay = jQuery("
",{id:"gfontsBatchRunProgressBarOverlay"}); + jQuery('body').append($gfontsBatchRunProgressbarOverlay); + $gfontsBatchRunProgressbarWrapper = jQuery("
",{id:"gfontsBatchRunProgressBarWrapper"}); + jQuery('body').append($gfontsBatchRunProgressbarWrapper); + $gfontsBatchRunProgressbar = jQuery('
Installation process of Google Fonts preview 0%
'); + jQuery($gfontsBatchRunProgressbarWrapper).append($gfontsBatchRunProgressbar); + + //var inProgress = false; + + $gfontsBatchRunProgressbar.progressbar({ + value: 0, + change: function() { + jQuery('#gfontsBatchRunProgressbarLabel').text( 'Installation process of Google Fonts preview ' + jQuery(this).progressbar("value") + '%' ); + }, + complete: function() { + jQuery('#gfontsBatchRunProgressbarLabel').text( 'Installation process of Google Font preview COMPLETE' ); + setTimeout(function(){ $gfontsBatchRunProgressbarWrapper.add($gfontsBatchRunProgressbarOverlay).fadeOut(1000) }, 1000); + } + }); + + postdata = { + action : 'store_gfonts_preview', + security : gfontsBatch.job.gfontsNonce, + gfontsCount: gfontsCount, + batchLimit : batchLimit, + lastBatchLimit: lastBatchLimit, + numRuns: numRuns, + currentRun: currentRun, + startIdx : 0 + }; + console.log(postdata); + gfontsBatchRun(postdata); + + + /* + if(typeof bibleGetOptionsFromServer !== 'undefined' && bibleGetOptionsFromServer.hasOwnProperty('options') && typeof bibleGetOptionsFromServer.options === 'object' && bibleGetOptionsFromServer.options.hasOwnProperty('googlefontsapi_key') && bibleGetOptionsFromServer.options.googlefontsapi_key != ''){ + //it's not possible to reuse the server side response from the google fonts API because it comes in late, after the localization of admin.js + //so we'll just have to do the job ourselves, given that we at least know our api key + jQuery.ajax({ + type: 'GET', + url: 'https://www.googleapis.com/webfonts/v1/webfonts', + data: {key: bibleGetOptionsFromServer.options.googlefontsapi_key }, + crossDomain: true, + headers: { + "accept": "application/json", + "Access-Control-Allow-Origin":"*" + }, + beforeSend: function() { + jQuery('#bibleget_ajax_spinner').show(); + }, + complete: function() { + jQuery('#bibleget_ajax_spinner').hide(); + }, + success: function(apiJSON){ + console.log('response received from Google Fonts API in admin.js ajax call, data returned: '); + console.log(apiJSON); + + gfontsBatch.job.gfontsJSON = apiJSON; + + + }, + error: function(xhr, ajaxOptions, thrownError){ + jQuery("#bibleget-settings-notification") + .fadeIn("slow") + .append('Communication with the Google Fonts API was not successful... ' + thrownError + ' ' + xhr.responseText); + jQuery(".bibleget-settings-notification-dismiss") + .click(function() { + jQuery("#bibleget-settings-notification").fadeOut("slow"); + }); + } + }); + } + else{ + console.log('we at least need the Google Fonts API key from the server, otherwise we can\'t do a thing'); + console.log('bibleGetOptionsFromServer:'); + console.log(bibleGetOptionsFromServer); + } + */ + + + + } + else{ + console.log('We do not seem to have a gfontsPreviewJob'); + console.log(typeof gfontsBatch); + console.log(gfontsBatch); + console.log('TEST CONDITION 1: typeof gfontsBatch !== \'undefined\''); + console.log(typeof gfontsBatch !== 'undefined'); + console.log('TEST CONDITION 2: typeof gfontsBatch === \'object\''); + console.log(typeof gfontsBatch === 'object'); + console.log('TEST CONDITION 3: gfontsBatch.hasOwnProperty(\'job\')'); + console.log(gfontsBatch.hasOwnProperty('job')); + console.log('TEST CONDITION 4: gfontsBatch.job.hasOwnProperty(\'gfontsPreviewJob\')'); + console.log(gfontsBatch.job.hasOwnProperty('job')); + console.log('TEST CONDITION 5: gfontsBatch.job.gfontsPreviewJob === true (an actual boolean value)'); + console.log(gfontsBatch.job.gfontsPreviewJob === true); + } + + +}); + +var myProgressInterval = null; +var myProgressValue= 0; +var $gfontsBatchRunProgressbarOverlay; +var $gfontsBatchRunProgressbar; +var $gfontsBatchRunProgressbarWrapper; + +var gfontsBatchRun= function(postdata){ + jQuery.ajax({ + type : 'POST', + url : gfontsBatch.job.ajax_url, + data : postdata, + dataType: 'json', + beforeSend : function() { + jQuery('#bibleget_ajax_spinner').show(); + $gfontsBatchRunProgressbar.progressbar("value"); + myProgressInterval = setInterval(updateGfontsBatchRunProgressbarProgress, 1500, postdata.currentRun, postdata.numRuns); + }, + complete : function() { + jQuery('#bibleget_ajax_spinner').hide(); + }, + success : function(returndata) { + clearInterval(myProgressInterval); + var returndataJSON = (typeof returndata !== 'object') ? JSON.parse(returndata) : returndata; + console.log('gfontsBatchRun success, returndataJSON:'); + console.log(returndataJSON); + if(returndataJSON !== null && typeof returndataJSON === 'object'){ + var thisRun = returndataJSON.hasOwnProperty('run') ? returndataJSON.run : false; + if(returndataJSON.hasOwnProperty('errorinfo') && returndataJSON.errorinfo !== false && returndataJSON.errorinfo.length > 0){ + console.log('Some errors were returned from ajax process run '+thisRun); + console.log(returndataJSON.errorinfo); + } + if(returndataJSON.hasOwnProperty('state')){ + switch(returndataJSON.state){ + case 'RUN_PROCESSED': + var maxUpdatePerRun = 100 / postdata.numRuns; + var maxedOutUpdateThisRun = maxUpdatePerRun * thisRun; + $gfontsBatchRunProgressbar.progressbar("value",maxedOutUpdateThisRun); + + if(thisRun && thisRun < postdata.numRuns){ + console.log('gfontsBatchRun was asked to do run '+postdata.currentRun+', and has let us know that it has in fact completed run '+thisRun+', now starting the next run'); + //check if we're doing the last run or not + if(++postdata.currentRun == postdata.numRuns){ + postdata.batchLimit == postdata.lastBatchLimit; + } + postdata.startIdx = postdata.startIdx + postdata.batchLimit; + + //Let's go for another round! + gfontsBatchRun(postdata); + } + else{ + console.log('We seem to have finished our job ahead of time? Please double check: numRuns= '+postdata.numRuns+', thisRun = '+thisRun); + } + break; + case 'COMPLETE': + $gfontsBatchRunProgressbar.progressbar("value",100); + + if(thisRun == postdata.numRuns){ + console.log('gfontsBatchRun has finished the job!'); + } + else{ + console.log('gfontsBatchRun is telling us that we have finished our job, but this might not be the case: numRuns= '+postdata.numRuns+', thisRun = '+thisRun); + } + break; + } + } + else{ + console.log('gfontsBatchRun: Now why do we not have any stateful info?'); + } + } + else{ + console.log('gfontsBatchRun: Now why do we not have any kind of feedback from the server side script?') + } + }, + error : function(xhr, ajaxOptions, thrownError) { + clearInterval(myProgressInterval); + jQuery("#bibleget-settings-notification") + .fadeIn("slow") + .append('Communication with the Google Fonts server was not successful... ERROR: ' + thrownError + ' ' + xhr.responseText); + jQuery(".bibleget-settings-notification-dismiss") + .click(function() { + jQuery("#bibleget-settings-notification").fadeOut("slow"); + }); + + } + }); +} -}); \ No newline at end of file +var updateGfontsBatchRunProgressbarProgress = function(currentRun,numRuns){ + //console.log('half second tick and $gfontsBatchRunProgressbar.progressbar("value") = '+$gfontsBatchRunProgressbar.progressbar("value")); + //console.log('half second tick and currentRun = '+currentRun+', numRuns = '+numRuns); + var maxUpdatePerRun = Math.floor(100 / parseInt(numRuns)); //if we do 4 runs, we will update no more than 25% of the progressbar for each run + //console.log('half second tick and maxUpdatePerRun = '+maxUpdatePerRun+', (maxUpdatePerRun * currentRun) = '+(maxUpdatePerRun * currentRun)); + if($gfontsBatchRunProgressbar.progressbar("value") < (maxUpdatePerRun * parseInt(currentRun))){ + var currentProgressBarValue = parseInt($gfontsBatchRunProgressbar.progressbar("value")); + $gfontsBatchRunProgressbar.progressbar("value",++currentProgressBarValue); + } +} diff --git a/js/he.js b/js/he.js index 83a8d32..29aa9ff 100644 --- a/js/he.js +++ b/js/he.js @@ -1,4 +1,4 @@ -/*! https://mths.be/he v1.1.1 by @mathias | MIT license */ +/*! https://mths.be/he v1.2.0 by @mathias | MIT license */ ;(function(root) { // Detect free variables `exports`. @@ -51,7 +51,7 @@ var regexInvalidEntity = /&#(?:[xX][^a-fA-F0-9]|[^0-9xX])/; var regexInvalidRawCodePoint = /[\0-\x08\x0B\x0E-\x1F\x7F-\x9F\uFDD0-\uFDEF\uFFFE\uFFFF]|[\uD83F\uD87F\uD8BF\uD8FF\uD93F\uD97F\uD9BF\uD9FF\uDA3F\uDA7F\uDABF\uDAFF\uDB3F\uDB7F\uDBBF\uDBFF][\uDFFE\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; - var regexDecode = /&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+);|&(Aacute|Agrave|Atilde|Ccedil|Eacute|Egrave|Iacute|Igrave|Ntilde|Oacute|Ograve|Oslash|Otilde|Uacute|Ugrave|Yacute|aacute|agrave|atilde|brvbar|ccedil|curren|divide|eacute|egrave|frac12|frac14|frac34|iacute|igrave|iquest|middot|ntilde|oacute|ograve|oslash|otilde|plusmn|uacute|ugrave|yacute|AElig|Acirc|Aring|Ecirc|Icirc|Ocirc|THORN|Ucirc|acirc|acute|aelig|aring|cedil|ecirc|icirc|iexcl|laquo|micro|ocirc|pound|raquo|szlig|thorn|times|ucirc|Auml|COPY|Euml|Iuml|Ouml|QUOT|Uuml|auml|cent|copy|euml|iuml|macr|nbsp|ordf|ordm|ouml|para|quot|sect|sup1|sup2|sup3|uuml|yuml|AMP|ETH|REG|amp|deg|eth|not|reg|shy|uml|yen|GT|LT|gt|lt)([=a-zA-Z0-9])?/g; + var regexDecode = /&(CounterClockwiseContourIntegral|DoubleLongLeftRightArrow|ClockwiseContourIntegral|NotNestedGreaterGreater|NotSquareSupersetEqual|DiacriticalDoubleAcute|NotRightTriangleEqual|NotSucceedsSlantEqual|NotPrecedesSlantEqual|CloseCurlyDoubleQuote|NegativeVeryThinSpace|DoubleContourIntegral|FilledVerySmallSquare|CapitalDifferentialD|OpenCurlyDoubleQuote|EmptyVerySmallSquare|NestedGreaterGreater|DoubleLongRightArrow|NotLeftTriangleEqual|NotGreaterSlantEqual|ReverseUpEquilibrium|DoubleLeftRightArrow|NotSquareSubsetEqual|NotDoubleVerticalBar|RightArrowLeftArrow|NotGreaterFullEqual|NotRightTriangleBar|SquareSupersetEqual|DownLeftRightVector|DoubleLongLeftArrow|leftrightsquigarrow|LeftArrowRightArrow|NegativeMediumSpace|blacktriangleright|RightDownVectorBar|PrecedesSlantEqual|RightDoubleBracket|SucceedsSlantEqual|NotLeftTriangleBar|RightTriangleEqual|SquareIntersection|RightDownTeeVector|ReverseEquilibrium|NegativeThickSpace|longleftrightarrow|Longleftrightarrow|LongLeftRightArrow|DownRightTeeVector|DownRightVectorBar|GreaterSlantEqual|SquareSubsetEqual|LeftDownVectorBar|LeftDoubleBracket|VerticalSeparator|rightleftharpoons|NotGreaterGreater|NotSquareSuperset|blacktriangleleft|blacktriangledown|NegativeThinSpace|LeftDownTeeVector|NotLessSlantEqual|leftrightharpoons|DoubleUpDownArrow|DoubleVerticalBar|LeftTriangleEqual|FilledSmallSquare|twoheadrightarrow|NotNestedLessLess|DownLeftTeeVector|DownLeftVectorBar|RightAngleBracket|NotTildeFullEqual|NotReverseElement|RightUpDownVector|DiacriticalTilde|NotSucceedsTilde|circlearrowright|NotPrecedesEqual|rightharpoondown|DoubleRightArrow|NotSucceedsEqual|NonBreakingSpace|NotRightTriangle|LessEqualGreater|RightUpTeeVector|LeftAngleBracket|GreaterFullEqual|DownArrowUpArrow|RightUpVectorBar|twoheadleftarrow|GreaterEqualLess|downharpoonright|RightTriangleBar|ntrianglerighteq|NotSupersetEqual|LeftUpDownVector|DiacriticalAcute|rightrightarrows|vartriangleright|UpArrowDownArrow|DiacriticalGrave|UnderParenthesis|EmptySmallSquare|LeftUpVectorBar|leftrightarrows|DownRightVector|downharpoonleft|trianglerighteq|ShortRightArrow|OverParenthesis|DoubleLeftArrow|DoubleDownArrow|NotSquareSubset|bigtriangledown|ntrianglelefteq|UpperRightArrow|curvearrowright|vartriangleleft|NotLeftTriangle|nleftrightarrow|LowerRightArrow|NotHumpDownHump|NotGreaterTilde|rightthreetimes|LeftUpTeeVector|NotGreaterEqual|straightepsilon|LeftTriangleBar|rightsquigarrow|ContourIntegral|rightleftarrows|CloseCurlyQuote|RightDownVector|LeftRightVector|nLeftrightarrow|leftharpoondown|circlearrowleft|SquareSuperset|OpenCurlyQuote|hookrightarrow|HorizontalLine|DiacriticalDot|NotLessGreater|ntriangleright|DoubleRightTee|InvisibleComma|InvisibleTimes|LowerLeftArrow|DownLeftVector|NotSubsetEqual|curvearrowleft|trianglelefteq|NotVerticalBar|TildeFullEqual|downdownarrows|NotGreaterLess|RightTeeVector|ZeroWidthSpace|looparrowright|LongRightArrow|doublebarwedge|ShortLeftArrow|ShortDownArrow|RightVectorBar|GreaterGreater|ReverseElement|rightharpoonup|LessSlantEqual|leftthreetimes|upharpoonright|rightarrowtail|LeftDownVector|Longrightarrow|NestedLessLess|UpperLeftArrow|nshortparallel|leftleftarrows|leftrightarrow|Leftrightarrow|LeftRightArrow|longrightarrow|upharpoonleft|RightArrowBar|ApplyFunction|LeftTeeVector|leftarrowtail|NotEqualTilde|varsubsetneqq|varsupsetneqq|RightTeeArrow|SucceedsEqual|SucceedsTilde|LeftVectorBar|SupersetEqual|hookleftarrow|DifferentialD|VerticalTilde|VeryThinSpace|blacktriangle|bigtriangleup|LessFullEqual|divideontimes|leftharpoonup|UpEquilibrium|ntriangleleft|RightTriangle|measuredangle|shortparallel|longleftarrow|Longleftarrow|LongLeftArrow|DoubleLeftTee|Poincareplane|PrecedesEqual|triangleright|DoubleUpArrow|RightUpVector|fallingdotseq|looparrowleft|PrecedesTilde|NotTildeEqual|NotTildeTilde|smallsetminus|Proportional|triangleleft|triangledown|UnderBracket|NotHumpEqual|exponentiale|ExponentialE|NotLessTilde|HilbertSpace|RightCeiling|blacklozenge|varsupsetneq|HumpDownHump|GreaterEqual|VerticalLine|LeftTeeArrow|NotLessEqual|DownTeeArrow|LeftTriangle|varsubsetneq|Intersection|NotCongruent|DownArrowBar|LeftUpVector|LeftArrowBar|risingdotseq|GreaterTilde|RoundImplies|SquareSubset|ShortUpArrow|NotSuperset|quaternions|precnapprox|backepsilon|preccurlyeq|OverBracket|blacksquare|MediumSpace|VerticalBar|circledcirc|circleddash|CircleMinus|CircleTimes|LessGreater|curlyeqprec|curlyeqsucc|diamondsuit|UpDownArrow|Updownarrow|RuleDelayed|Rrightarrow|updownarrow|RightVector|nRightarrow|nrightarrow|eqslantless|LeftCeiling|Equilibrium|SmallCircle|expectation|NotSucceeds|thickapprox|GreaterLess|SquareUnion|NotPrecedes|NotLessLess|straightphi|succnapprox|succcurlyeq|SubsetEqual|sqsupseteq|Proportion|Laplacetrf|ImaginaryI|supsetneqq|NotGreater|gtreqqless|NotElement|ThickSpace|TildeEqual|TildeTilde|Fouriertrf|rmoustache|EqualTilde|eqslantgtr|UnderBrace|LeftVector|UpArrowBar|nLeftarrow|nsubseteqq|subsetneqq|nsupseteqq|nleftarrow|succapprox|lessapprox|UpTeeArrow|upuparrows|curlywedge|lesseqqgtr|varepsilon|varnothing|RightFloor|complement|CirclePlus|sqsubseteq|Lleftarrow|circledast|RightArrow|Rightarrow|rightarrow|lmoustache|Bernoullis|precapprox|mapstoleft|mapstodown|longmapsto|dotsquare|downarrow|DoubleDot|nsubseteq|supsetneq|leftarrow|nsupseteq|subsetneq|ThinSpace|ngeqslant|subseteqq|HumpEqual|NotSubset|triangleq|NotCupCap|lesseqgtr|heartsuit|TripleDot|Leftarrow|Coproduct|Congruent|varpropto|complexes|gvertneqq|LeftArrow|LessTilde|supseteqq|MinusPlus|CircleDot|nleqslant|NotExists|gtreqless|nparallel|UnionPlus|LeftFloor|checkmark|CenterDot|centerdot|Mellintrf|gtrapprox|bigotimes|OverBrace|spadesuit|therefore|pitchfork|rationals|PlusMinus|Backslash|Therefore|DownBreve|backsimeq|backprime|DownArrow|nshortmid|Downarrow|lvertneqq|eqvparsl|imagline|imagpart|infintie|integers|Integral|intercal|LessLess|Uarrocir|intlarhk|sqsupset|angmsdaf|sqsubset|llcorner|vartheta|cupbrcap|lnapprox|Superset|SuchThat|succnsim|succneqq|angmsdag|biguplus|curlyvee|trpezium|Succeeds|NotTilde|bigwedge|angmsdah|angrtvbd|triminus|cwconint|fpartint|lrcorner|smeparsl|subseteq|urcorner|lurdshar|laemptyv|DDotrahd|approxeq|ldrushar|awconint|mapstoup|backcong|shortmid|triangle|geqslant|gesdotol|timesbar|circledR|circledS|setminus|multimap|naturals|scpolint|ncongdot|RightTee|boxminus|gnapprox|boxtimes|andslope|thicksim|angmsdaa|varsigma|cirfnint|rtriltri|angmsdab|rppolint|angmsdac|barwedge|drbkarow|clubsuit|thetasym|bsolhsub|capbrcup|dzigrarr|doteqdot|DotEqual|dotminus|UnderBar|NotEqual|realpart|otimesas|ulcorner|hksearow|hkswarow|parallel|PartialD|elinters|emptyset|plusacir|bbrktbrk|angmsdad|pointint|bigoplus|angmsdae|Precedes|bigsqcup|varkappa|notindot|supseteq|precneqq|precnsim|profalar|profline|profsurf|leqslant|lesdotor|raemptyv|subplus|notnivb|notnivc|subrarr|zigrarr|vzigzag|submult|subedot|Element|between|cirscir|larrbfs|larrsim|lotimes|lbrksld|lbrkslu|lozenge|ldrdhar|dbkarow|bigcirc|epsilon|simrarr|simplus|ltquest|Epsilon|luruhar|gtquest|maltese|npolint|eqcolon|npreceq|bigodot|ddagger|gtrless|bnequiv|harrcir|ddotseq|equivDD|backsim|demptyv|nsqsube|nsqsupe|Upsilon|nsubset|upsilon|minusdu|nsucceq|swarrow|nsupset|coloneq|searrow|boxplus|napprox|natural|asympeq|alefsym|congdot|nearrow|bigstar|diamond|supplus|tritime|LeftTee|nvinfin|triplus|NewLine|nvltrie|nvrtrie|nwarrow|nexists|Diamond|ruluhar|Implies|supmult|angzarr|suplarr|suphsub|questeq|because|digamma|Because|olcross|bemptyv|omicron|Omicron|rotimes|NoBreak|intprod|angrtvb|orderof|uwangle|suphsol|lesdoto|orslope|DownTee|realine|cudarrl|rdldhar|OverBar|supedot|lessdot|supdsub|topfork|succsim|rbrkslu|rbrksld|pertenk|cudarrr|isindot|planckh|lessgtr|pluscir|gesdoto|plussim|plustwo|lesssim|cularrp|rarrsim|Cayleys|notinva|notinvb|notinvc|UpArrow|Uparrow|uparrow|NotLess|dwangle|precsim|Product|curarrm|Cconint|dotplus|rarrbfs|ccupssm|Cedilla|cemptyv|notniva|quatint|frac35|frac38|frac45|frac56|frac58|frac78|tridot|xoplus|gacute|gammad|Gammad|lfisht|lfloor|bigcup|sqsupe|gbreve|Gbreve|lharul|sqsube|sqcups|Gcedil|apacir|llhard|lmidot|Lmidot|lmoust|andand|sqcaps|approx|Abreve|spades|circeq|tprime|divide|topcir|Assign|topbot|gesdot|divonx|xuplus|timesd|gesles|atilde|solbar|SOFTcy|loplus|timesb|lowast|lowbar|dlcorn|dlcrop|softcy|dollar|lparlt|thksim|lrhard|Atilde|lsaquo|smashp|bigvee|thinsp|wreath|bkarow|lsquor|lstrok|Lstrok|lthree|ltimes|ltlarr|DotDot|simdot|ltrPar|weierp|xsqcup|angmsd|sigmav|sigmaf|zeetrf|Zcaron|zcaron|mapsto|vsupne|thetav|cirmid|marker|mcomma|Zacute|vsubnE|there4|gtlPar|vsubne|bottom|gtrarr|SHCHcy|shchcy|midast|midcir|middot|minusb|minusd|gtrdot|bowtie|sfrown|mnplus|models|colone|seswar|Colone|mstpos|searhk|gtrsim|nacute|Nacute|boxbox|telrec|hairsp|Tcedil|nbumpe|scnsim|ncaron|Ncaron|ncedil|Ncedil|hamilt|Scedil|nearhk|hardcy|HARDcy|tcedil|Tcaron|commat|nequiv|nesear|tcaron|target|hearts|nexist|varrho|scedil|Scaron|scaron|hellip|Sacute|sacute|hercon|swnwar|compfn|rtimes|rthree|rsquor|rsaquo|zacute|wedgeq|homtht|barvee|barwed|Barwed|rpargt|horbar|conint|swarhk|roplus|nltrie|hslash|hstrok|Hstrok|rmoust|Conint|bprime|hybull|hyphen|iacute|Iacute|supsup|supsub|supsim|varphi|coprod|brvbar|agrave|Supset|supset|igrave|Igrave|notinE|Agrave|iiiint|iinfin|copysr|wedbar|Verbar|vangrt|becaus|incare|verbar|inodot|bullet|drcorn|intcal|drcrop|cularr|vellip|Utilde|bumpeq|cupcap|dstrok|Dstrok|CupCap|cupcup|cupdot|eacute|Eacute|supdot|iquest|easter|ecaron|Ecaron|ecolon|isinsv|utilde|itilde|Itilde|curarr|succeq|Bumpeq|cacute|ulcrop|nparsl|Cacute|nprcue|egrave|Egrave|nrarrc|nrarrw|subsup|subsub|nrtrie|jsercy|nsccue|Jsercy|kappav|kcedil|Kcedil|subsim|ulcorn|nsimeq|egsdot|veebar|kgreen|capand|elsdot|Subset|subset|curren|aacute|lacute|Lacute|emptyv|ntilde|Ntilde|lagran|lambda|Lambda|capcap|Ugrave|langle|subdot|emsp13|numero|emsp14|nvdash|nvDash|nVdash|nVDash|ugrave|ufisht|nvHarr|larrfs|nvlArr|larrhk|larrlp|larrpl|nvrArr|Udblac|nwarhk|larrtl|nwnear|oacute|Oacute|latail|lAtail|sstarf|lbrace|odblac|Odblac|lbrack|udblac|odsold|eparsl|lcaron|Lcaron|ograve|Ograve|lcedil|Lcedil|Aacute|ssmile|ssetmn|squarf|ldquor|capcup|ominus|cylcty|rharul|eqcirc|dagger|rfloor|rfisht|Dagger|daleth|equals|origof|capdot|equest|dcaron|Dcaron|rdquor|oslash|Oslash|otilde|Otilde|otimes|Otimes|urcrop|Ubreve|ubreve|Yacute|Uacute|uacute|Rcedil|rcedil|urcorn|parsim|Rcaron|Vdashl|rcaron|Tstrok|percnt|period|permil|Exists|yacute|rbrack|rbrace|phmmat|ccaron|Ccaron|planck|ccedil|plankv|tstrok|female|plusdo|plusdu|ffilig|plusmn|ffllig|Ccedil|rAtail|dfisht|bernou|ratail|Rarrtl|rarrtl|angsph|rarrpl|rarrlp|rarrhk|xwedge|xotime|forall|ForAll|Vvdash|vsupnE|preceq|bigcap|frac12|frac13|frac14|primes|rarrfs|prnsim|frac15|Square|frac16|square|lesdot|frac18|frac23|propto|prurel|rarrap|rangle|puncsp|frac25|Racute|qprime|racute|lesges|frac34|abreve|AElig|eqsim|utdot|setmn|urtri|Equal|Uring|seArr|uring|searr|dashv|Dashv|mumap|nabla|iogon|Iogon|sdote|sdotb|scsim|napid|napos|equiv|natur|Acirc|dblac|erarr|nbump|iprod|erDot|ucirc|awint|esdot|angrt|ncong|isinE|scnap|Scirc|scirc|ndash|isins|Ubrcy|nearr|neArr|isinv|nedot|ubrcy|acute|Ycirc|iukcy|Iukcy|xutri|nesim|caret|jcirc|Jcirc|caron|twixt|ddarr|sccue|exist|jmath|sbquo|ngeqq|angst|ccaps|lceil|ngsim|UpTee|delta|Delta|rtrif|nharr|nhArr|nhpar|rtrie|jukcy|Jukcy|kappa|rsquo|Kappa|nlarr|nlArr|TSHcy|rrarr|aogon|Aogon|fflig|xrarr|tshcy|ccirc|nleqq|filig|upsih|nless|dharl|nlsim|fjlig|ropar|nltri|dharr|robrk|roarr|fllig|fltns|roang|rnmid|subnE|subne|lAarr|trisb|Ccirc|acirc|ccups|blank|VDash|forkv|Vdash|langd|cedil|blk12|blk14|laquo|strns|diams|notin|vDash|larrb|blk34|block|disin|uplus|vdash|vBarv|aelig|starf|Wedge|check|xrArr|lates|lbarr|lBarr|notni|lbbrk|bcong|frasl|lbrke|frown|vrtri|vprop|vnsup|gamma|Gamma|wedge|xodot|bdquo|srarr|doteq|ldquo|boxdl|boxdL|gcirc|Gcirc|boxDl|boxDL|boxdr|boxdR|boxDr|TRADE|trade|rlhar|boxDR|vnsub|npart|vltri|rlarr|boxhd|boxhD|nprec|gescc|nrarr|nrArr|boxHd|boxHD|boxhu|boxhU|nrtri|boxHu|clubs|boxHU|times|colon|Colon|gimel|xlArr|Tilde|nsime|tilde|nsmid|nspar|THORN|thorn|xlarr|nsube|nsubE|thkap|xhArr|comma|nsucc|boxul|boxuL|nsupe|nsupE|gneqq|gnsim|boxUl|boxUL|grave|boxur|boxuR|boxUr|boxUR|lescc|angle|bepsi|boxvh|varpi|boxvH|numsp|Theta|gsime|gsiml|theta|boxVh|boxVH|boxvl|gtcir|gtdot|boxvL|boxVl|boxVL|crarr|cross|Cross|nvsim|boxvr|nwarr|nwArr|sqsup|dtdot|Uogon|lhard|lharu|dtrif|ocirc|Ocirc|lhblk|duarr|odash|sqsub|Hacek|sqcup|llarr|duhar|oelig|OElig|ofcir|boxvR|uogon|lltri|boxVr|csube|uuarr|ohbar|csupe|ctdot|olarr|olcir|harrw|oline|sqcap|omacr|Omacr|omega|Omega|boxVR|aleph|lneqq|lnsim|loang|loarr|rharu|lobrk|hcirc|operp|oplus|rhard|Hcirc|orarr|Union|order|ecirc|Ecirc|cuepr|szlig|cuesc|breve|reals|eDDot|Breve|hoarr|lopar|utrif|rdquo|Umacr|umacr|efDot|swArr|ultri|alpha|rceil|ovbar|swarr|Wcirc|wcirc|smtes|smile|bsemi|lrarr|aring|parsl|lrhar|bsime|uhblk|lrtri|cupor|Aring|uharr|uharl|slarr|rbrke|bsolb|lsime|rbbrk|RBarr|lsimg|phone|rBarr|rbarr|icirc|lsquo|Icirc|emacr|Emacr|ratio|simne|plusb|simlE|simgE|simeq|pluse|ltcir|ltdot|empty|xharr|xdtri|iexcl|Alpha|ltrie|rarrw|pound|ltrif|xcirc|bumpe|prcue|bumpE|asymp|amacr|cuvee|Sigma|sigma|iiint|udhar|iiota|ijlig|IJlig|supnE|imacr|Imacr|prime|Prime|image|prnap|eogon|Eogon|rarrc|mdash|mDDot|cuwed|imath|supne|imped|Amacr|udarr|prsim|micro|rarrb|cwint|raquo|infin|eplus|range|rangd|Ucirc|radic|minus|amalg|veeeq|rAarr|epsiv|ycirc|quest|sharp|quot|zwnj|Qscr|race|qscr|Qopf|qopf|qint|rang|Rang|Zscr|zscr|Zopf|zopf|rarr|rArr|Rarr|Pscr|pscr|prop|prod|prnE|prec|ZHcy|zhcy|prap|Zeta|zeta|Popf|popf|Zdot|plus|zdot|Yuml|yuml|phiv|YUcy|yucy|Yscr|yscr|perp|Yopf|yopf|part|para|YIcy|Ouml|rcub|yicy|YAcy|rdca|ouml|osol|Oscr|rdsh|yacy|real|oscr|xvee|andd|rect|andv|Xscr|oror|ordm|ordf|xscr|ange|aopf|Aopf|rHar|Xopf|opar|Oopf|xopf|xnis|rhov|oopf|omid|xmap|oint|apid|apos|ogon|ascr|Ascr|odot|odiv|xcup|xcap|ocir|oast|nvlt|nvle|nvgt|nvge|nvap|Wscr|wscr|auml|ntlg|ntgl|nsup|nsub|nsim|Nscr|nscr|nsce|Wopf|ring|npre|wopf|npar|Auml|Barv|bbrk|Nopf|nopf|nmid|nLtv|beta|ropf|Ropf|Beta|beth|nles|rpar|nleq|bnot|bNot|nldr|NJcy|rscr|Rscr|Vscr|vscr|rsqb|njcy|bopf|nisd|Bopf|rtri|Vopf|nGtv|ngtr|vopf|boxh|boxH|boxv|nges|ngeq|boxV|bscr|scap|Bscr|bsim|Vert|vert|bsol|bull|bump|caps|cdot|ncup|scnE|ncap|nbsp|napE|Cdot|cent|sdot|Vbar|nang|vBar|chcy|Mscr|mscr|sect|semi|CHcy|Mopf|mopf|sext|circ|cire|mldr|mlcp|cirE|comp|shcy|SHcy|vArr|varr|cong|copf|Copf|copy|COPY|malt|male|macr|lvnE|cscr|ltri|sime|ltcc|simg|Cscr|siml|csub|Uuml|lsqb|lsim|uuml|csup|Lscr|lscr|utri|smid|lpar|cups|smte|lozf|darr|Lopf|Uscr|solb|lopf|sopf|Sopf|lneq|uscr|spar|dArr|lnap|Darr|dash|Sqrt|LJcy|ljcy|lHar|dHar|Upsi|upsi|diam|lesg|djcy|DJcy|leqq|dopf|Dopf|dscr|Dscr|dscy|ldsh|ldca|squf|DScy|sscr|Sscr|dsol|lcub|late|star|Star|Uopf|Larr|lArr|larr|uopf|dtri|dzcy|sube|subE|Lang|lang|Kscr|kscr|Kopf|kopf|KJcy|kjcy|KHcy|khcy|DZcy|ecir|edot|eDot|Jscr|jscr|succ|Jopf|jopf|Edot|uHar|emsp|ensp|Iuml|iuml|eopf|isin|Iscr|iscr|Eopf|epar|sung|epsi|escr|sup1|sup2|sup3|Iota|iota|supe|supE|Iopf|iopf|IOcy|iocy|Escr|esim|Esim|imof|Uarr|QUOT|uArr|uarr|euml|IEcy|iecy|Idot|Euml|euro|excl|Hscr|hscr|Hopf|hopf|TScy|tscy|Tscr|hbar|tscr|flat|tbrk|fnof|hArr|harr|half|fopf|Fopf|tdot|gvnE|fork|trie|gtcc|fscr|Fscr|gdot|gsim|Gscr|gscr|Gopf|gopf|gneq|Gdot|tosa|gnap|Topf|topf|geqq|toea|GJcy|gjcy|tint|gesl|mid|Sfr|ggg|top|ges|gla|glE|glj|geq|gne|gEl|gel|gnE|Gcy|gcy|gap|Tfr|tfr|Tcy|tcy|Hat|Tau|Ffr|tau|Tab|hfr|Hfr|ffr|Fcy|fcy|icy|Icy|iff|ETH|eth|ifr|Ifr|Eta|eta|int|Int|Sup|sup|ucy|Ucy|Sum|sum|jcy|ENG|ufr|Ufr|eng|Jcy|jfr|els|ell|egs|Efr|efr|Jfr|uml|kcy|Kcy|Ecy|ecy|kfr|Kfr|lap|Sub|sub|lat|lcy|Lcy|leg|Dot|dot|lEg|leq|les|squ|div|die|lfr|Lfr|lgE|Dfr|dfr|Del|deg|Dcy|dcy|lne|lnE|sol|loz|smt|Cup|lrm|cup|lsh|Lsh|sim|shy|map|Map|mcy|Mcy|mfr|Mfr|mho|gfr|Gfr|sfr|cir|Chi|chi|nap|Cfr|vcy|Vcy|cfr|Scy|scy|ncy|Ncy|vee|Vee|Cap|cap|nfr|scE|sce|Nfr|nge|ngE|nGg|vfr|Vfr|ngt|bot|nGt|nis|niv|Rsh|rsh|nle|nlE|bne|Bfr|bfr|nLl|nlt|nLt|Bcy|bcy|not|Not|rlm|wfr|Wfr|npr|nsc|num|ocy|ast|Ocy|ofr|xfr|Xfr|Ofr|ogt|ohm|apE|olt|Rho|ape|rho|Rfr|rfr|ord|REG|ang|reg|orv|And|and|AMP|Rcy|amp|Afr|ycy|Ycy|yen|yfr|Yfr|rcy|par|pcy|Pcy|pfr|Pfr|phi|Phi|afr|Acy|acy|zcy|Zcy|piv|acE|acd|zfr|Zfr|pre|prE|psi|Psi|qfr|Qfr|zwj|Or|ge|Gg|gt|gg|el|oS|lt|Lt|LT|Re|lg|gl|eg|ne|Im|it|le|DD|wp|wr|nu|Nu|dd|lE|Sc|sc|pi|Pi|ee|af|ll|Ll|rx|gE|xi|pm|Xi|ic|pr|Pr|in|ni|mp|mu|ac|Mu|or|ap|Gt|GT|ii);|&(Aacute|Agrave|Atilde|Ccedil|Eacute|Egrave|Iacute|Igrave|Ntilde|Oacute|Ograve|Oslash|Otilde|Uacute|Ugrave|Yacute|aacute|agrave|atilde|brvbar|ccedil|curren|divide|eacute|egrave|frac12|frac14|frac34|iacute|igrave|iquest|middot|ntilde|oacute|ograve|oslash|otilde|plusmn|uacute|ugrave|yacute|AElig|Acirc|Aring|Ecirc|Icirc|Ocirc|THORN|Ucirc|acirc|acute|aelig|aring|cedil|ecirc|icirc|iexcl|laquo|micro|ocirc|pound|raquo|szlig|thorn|times|ucirc|Auml|COPY|Euml|Iuml|Ouml|QUOT|Uuml|auml|cent|copy|euml|iuml|macr|nbsp|ordf|ordm|ouml|para|quot|sect|sup1|sup2|sup3|uuml|yuml|AMP|ETH|REG|amp|deg|eth|not|reg|shy|uml|yen|GT|LT|gt|lt)(?!;)([=a-zA-Z0-9]?)|&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+)/g; var decodeMap = {'aacute':'\xE1','Aacute':'\xC1','abreve':'\u0103','Abreve':'\u0102','ac':'\u223E','acd':'\u223F','acE':'\u223E\u0333','acirc':'\xE2','Acirc':'\xC2','acute':'\xB4','acy':'\u0430','Acy':'\u0410','aelig':'\xE6','AElig':'\xC6','af':'\u2061','afr':'\uD835\uDD1E','Afr':'\uD835\uDD04','agrave':'\xE0','Agrave':'\xC0','alefsym':'\u2135','aleph':'\u2135','alpha':'\u03B1','Alpha':'\u0391','amacr':'\u0101','Amacr':'\u0100','amalg':'\u2A3F','amp':'&','AMP':'&','and':'\u2227','And':'\u2A53','andand':'\u2A55','andd':'\u2A5C','andslope':'\u2A58','andv':'\u2A5A','ang':'\u2220','ange':'\u29A4','angle':'\u2220','angmsd':'\u2221','angmsdaa':'\u29A8','angmsdab':'\u29A9','angmsdac':'\u29AA','angmsdad':'\u29AB','angmsdae':'\u29AC','angmsdaf':'\u29AD','angmsdag':'\u29AE','angmsdah':'\u29AF','angrt':'\u221F','angrtvb':'\u22BE','angrtvbd':'\u299D','angsph':'\u2222','angst':'\xC5','angzarr':'\u237C','aogon':'\u0105','Aogon':'\u0104','aopf':'\uD835\uDD52','Aopf':'\uD835\uDD38','ap':'\u2248','apacir':'\u2A6F','ape':'\u224A','apE':'\u2A70','apid':'\u224B','apos':'\'','ApplyFunction':'\u2061','approx':'\u2248','approxeq':'\u224A','aring':'\xE5','Aring':'\xC5','ascr':'\uD835\uDCB6','Ascr':'\uD835\uDC9C','Assign':'\u2254','ast':'*','asymp':'\u2248','asympeq':'\u224D','atilde':'\xE3','Atilde':'\xC3','auml':'\xE4','Auml':'\xC4','awconint':'\u2233','awint':'\u2A11','backcong':'\u224C','backepsilon':'\u03F6','backprime':'\u2035','backsim':'\u223D','backsimeq':'\u22CD','Backslash':'\u2216','Barv':'\u2AE7','barvee':'\u22BD','barwed':'\u2305','Barwed':'\u2306','barwedge':'\u2305','bbrk':'\u23B5','bbrktbrk':'\u23B6','bcong':'\u224C','bcy':'\u0431','Bcy':'\u0411','bdquo':'\u201E','becaus':'\u2235','because':'\u2235','Because':'\u2235','bemptyv':'\u29B0','bepsi':'\u03F6','bernou':'\u212C','Bernoullis':'\u212C','beta':'\u03B2','Beta':'\u0392','beth':'\u2136','between':'\u226C','bfr':'\uD835\uDD1F','Bfr':'\uD835\uDD05','bigcap':'\u22C2','bigcirc':'\u25EF','bigcup':'\u22C3','bigodot':'\u2A00','bigoplus':'\u2A01','bigotimes':'\u2A02','bigsqcup':'\u2A06','bigstar':'\u2605','bigtriangledown':'\u25BD','bigtriangleup':'\u25B3','biguplus':'\u2A04','bigvee':'\u22C1','bigwedge':'\u22C0','bkarow':'\u290D','blacklozenge':'\u29EB','blacksquare':'\u25AA','blacktriangle':'\u25B4','blacktriangledown':'\u25BE','blacktriangleleft':'\u25C2','blacktriangleright':'\u25B8','blank':'\u2423','blk12':'\u2592','blk14':'\u2591','blk34':'\u2593','block':'\u2588','bne':'=\u20E5','bnequiv':'\u2261\u20E5','bnot':'\u2310','bNot':'\u2AED','bopf':'\uD835\uDD53','Bopf':'\uD835\uDD39','bot':'\u22A5','bottom':'\u22A5','bowtie':'\u22C8','boxbox':'\u29C9','boxdl':'\u2510','boxdL':'\u2555','boxDl':'\u2556','boxDL':'\u2557','boxdr':'\u250C','boxdR':'\u2552','boxDr':'\u2553','boxDR':'\u2554','boxh':'\u2500','boxH':'\u2550','boxhd':'\u252C','boxhD':'\u2565','boxHd':'\u2564','boxHD':'\u2566','boxhu':'\u2534','boxhU':'\u2568','boxHu':'\u2567','boxHU':'\u2569','boxminus':'\u229F','boxplus':'\u229E','boxtimes':'\u22A0','boxul':'\u2518','boxuL':'\u255B','boxUl':'\u255C','boxUL':'\u255D','boxur':'\u2514','boxuR':'\u2558','boxUr':'\u2559','boxUR':'\u255A','boxv':'\u2502','boxV':'\u2551','boxvh':'\u253C','boxvH':'\u256A','boxVh':'\u256B','boxVH':'\u256C','boxvl':'\u2524','boxvL':'\u2561','boxVl':'\u2562','boxVL':'\u2563','boxvr':'\u251C','boxvR':'\u255E','boxVr':'\u255F','boxVR':'\u2560','bprime':'\u2035','breve':'\u02D8','Breve':'\u02D8','brvbar':'\xA6','bscr':'\uD835\uDCB7','Bscr':'\u212C','bsemi':'\u204F','bsim':'\u223D','bsime':'\u22CD','bsol':'\\','bsolb':'\u29C5','bsolhsub':'\u27C8','bull':'\u2022','bullet':'\u2022','bump':'\u224E','bumpe':'\u224F','bumpE':'\u2AAE','bumpeq':'\u224F','Bumpeq':'\u224E','cacute':'\u0107','Cacute':'\u0106','cap':'\u2229','Cap':'\u22D2','capand':'\u2A44','capbrcup':'\u2A49','capcap':'\u2A4B','capcup':'\u2A47','capdot':'\u2A40','CapitalDifferentialD':'\u2145','caps':'\u2229\uFE00','caret':'\u2041','caron':'\u02C7','Cayleys':'\u212D','ccaps':'\u2A4D','ccaron':'\u010D','Ccaron':'\u010C','ccedil':'\xE7','Ccedil':'\xC7','ccirc':'\u0109','Ccirc':'\u0108','Cconint':'\u2230','ccups':'\u2A4C','ccupssm':'\u2A50','cdot':'\u010B','Cdot':'\u010A','cedil':'\xB8','Cedilla':'\xB8','cemptyv':'\u29B2','cent':'\xA2','centerdot':'\xB7','CenterDot':'\xB7','cfr':'\uD835\uDD20','Cfr':'\u212D','chcy':'\u0447','CHcy':'\u0427','check':'\u2713','checkmark':'\u2713','chi':'\u03C7','Chi':'\u03A7','cir':'\u25CB','circ':'\u02C6','circeq':'\u2257','circlearrowleft':'\u21BA','circlearrowright':'\u21BB','circledast':'\u229B','circledcirc':'\u229A','circleddash':'\u229D','CircleDot':'\u2299','circledR':'\xAE','circledS':'\u24C8','CircleMinus':'\u2296','CirclePlus':'\u2295','CircleTimes':'\u2297','cire':'\u2257','cirE':'\u29C3','cirfnint':'\u2A10','cirmid':'\u2AEF','cirscir':'\u29C2','ClockwiseContourIntegral':'\u2232','CloseCurlyDoubleQuote':'\u201D','CloseCurlyQuote':'\u2019','clubs':'\u2663','clubsuit':'\u2663','colon':':','Colon':'\u2237','colone':'\u2254','Colone':'\u2A74','coloneq':'\u2254','comma':',','commat':'@','comp':'\u2201','compfn':'\u2218','complement':'\u2201','complexes':'\u2102','cong':'\u2245','congdot':'\u2A6D','Congruent':'\u2261','conint':'\u222E','Conint':'\u222F','ContourIntegral':'\u222E','copf':'\uD835\uDD54','Copf':'\u2102','coprod':'\u2210','Coproduct':'\u2210','copy':'\xA9','COPY':'\xA9','copysr':'\u2117','CounterClockwiseContourIntegral':'\u2233','crarr':'\u21B5','cross':'\u2717','Cross':'\u2A2F','cscr':'\uD835\uDCB8','Cscr':'\uD835\uDC9E','csub':'\u2ACF','csube':'\u2AD1','csup':'\u2AD0','csupe':'\u2AD2','ctdot':'\u22EF','cudarrl':'\u2938','cudarrr':'\u2935','cuepr':'\u22DE','cuesc':'\u22DF','cularr':'\u21B6','cularrp':'\u293D','cup':'\u222A','Cup':'\u22D3','cupbrcap':'\u2A48','cupcap':'\u2A46','CupCap':'\u224D','cupcup':'\u2A4A','cupdot':'\u228D','cupor':'\u2A45','cups':'\u222A\uFE00','curarr':'\u21B7','curarrm':'\u293C','curlyeqprec':'\u22DE','curlyeqsucc':'\u22DF','curlyvee':'\u22CE','curlywedge':'\u22CF','curren':'\xA4','curvearrowleft':'\u21B6','curvearrowright':'\u21B7','cuvee':'\u22CE','cuwed':'\u22CF','cwconint':'\u2232','cwint':'\u2231','cylcty':'\u232D','dagger':'\u2020','Dagger':'\u2021','daleth':'\u2138','darr':'\u2193','dArr':'\u21D3','Darr':'\u21A1','dash':'\u2010','dashv':'\u22A3','Dashv':'\u2AE4','dbkarow':'\u290F','dblac':'\u02DD','dcaron':'\u010F','Dcaron':'\u010E','dcy':'\u0434','Dcy':'\u0414','dd':'\u2146','DD':'\u2145','ddagger':'\u2021','ddarr':'\u21CA','DDotrahd':'\u2911','ddotseq':'\u2A77','deg':'\xB0','Del':'\u2207','delta':'\u03B4','Delta':'\u0394','demptyv':'\u29B1','dfisht':'\u297F','dfr':'\uD835\uDD21','Dfr':'\uD835\uDD07','dHar':'\u2965','dharl':'\u21C3','dharr':'\u21C2','DiacriticalAcute':'\xB4','DiacriticalDot':'\u02D9','DiacriticalDoubleAcute':'\u02DD','DiacriticalGrave':'`','DiacriticalTilde':'\u02DC','diam':'\u22C4','diamond':'\u22C4','Diamond':'\u22C4','diamondsuit':'\u2666','diams':'\u2666','die':'\xA8','DifferentialD':'\u2146','digamma':'\u03DD','disin':'\u22F2','div':'\xF7','divide':'\xF7','divideontimes':'\u22C7','divonx':'\u22C7','djcy':'\u0452','DJcy':'\u0402','dlcorn':'\u231E','dlcrop':'\u230D','dollar':'$','dopf':'\uD835\uDD55','Dopf':'\uD835\uDD3B','dot':'\u02D9','Dot':'\xA8','DotDot':'\u20DC','doteq':'\u2250','doteqdot':'\u2251','DotEqual':'\u2250','dotminus':'\u2238','dotplus':'\u2214','dotsquare':'\u22A1','doublebarwedge':'\u2306','DoubleContourIntegral':'\u222F','DoubleDot':'\xA8','DoubleDownArrow':'\u21D3','DoubleLeftArrow':'\u21D0','DoubleLeftRightArrow':'\u21D4','DoubleLeftTee':'\u2AE4','DoubleLongLeftArrow':'\u27F8','DoubleLongLeftRightArrow':'\u27FA','DoubleLongRightArrow':'\u27F9','DoubleRightArrow':'\u21D2','DoubleRightTee':'\u22A8','DoubleUpArrow':'\u21D1','DoubleUpDownArrow':'\u21D5','DoubleVerticalBar':'\u2225','downarrow':'\u2193','Downarrow':'\u21D3','DownArrow':'\u2193','DownArrowBar':'\u2913','DownArrowUpArrow':'\u21F5','DownBreve':'\u0311','downdownarrows':'\u21CA','downharpoonleft':'\u21C3','downharpoonright':'\u21C2','DownLeftRightVector':'\u2950','DownLeftTeeVector':'\u295E','DownLeftVector':'\u21BD','DownLeftVectorBar':'\u2956','DownRightTeeVector':'\u295F','DownRightVector':'\u21C1','DownRightVectorBar':'\u2957','DownTee':'\u22A4','DownTeeArrow':'\u21A7','drbkarow':'\u2910','drcorn':'\u231F','drcrop':'\u230C','dscr':'\uD835\uDCB9','Dscr':'\uD835\uDC9F','dscy':'\u0455','DScy':'\u0405','dsol':'\u29F6','dstrok':'\u0111','Dstrok':'\u0110','dtdot':'\u22F1','dtri':'\u25BF','dtrif':'\u25BE','duarr':'\u21F5','duhar':'\u296F','dwangle':'\u29A6','dzcy':'\u045F','DZcy':'\u040F','dzigrarr':'\u27FF','eacute':'\xE9','Eacute':'\xC9','easter':'\u2A6E','ecaron':'\u011B','Ecaron':'\u011A','ecir':'\u2256','ecirc':'\xEA','Ecirc':'\xCA','ecolon':'\u2255','ecy':'\u044D','Ecy':'\u042D','eDDot':'\u2A77','edot':'\u0117','eDot':'\u2251','Edot':'\u0116','ee':'\u2147','efDot':'\u2252','efr':'\uD835\uDD22','Efr':'\uD835\uDD08','eg':'\u2A9A','egrave':'\xE8','Egrave':'\xC8','egs':'\u2A96','egsdot':'\u2A98','el':'\u2A99','Element':'\u2208','elinters':'\u23E7','ell':'\u2113','els':'\u2A95','elsdot':'\u2A97','emacr':'\u0113','Emacr':'\u0112','empty':'\u2205','emptyset':'\u2205','EmptySmallSquare':'\u25FB','emptyv':'\u2205','EmptyVerySmallSquare':'\u25AB','emsp':'\u2003','emsp13':'\u2004','emsp14':'\u2005','eng':'\u014B','ENG':'\u014A','ensp':'\u2002','eogon':'\u0119','Eogon':'\u0118','eopf':'\uD835\uDD56','Eopf':'\uD835\uDD3C','epar':'\u22D5','eparsl':'\u29E3','eplus':'\u2A71','epsi':'\u03B5','epsilon':'\u03B5','Epsilon':'\u0395','epsiv':'\u03F5','eqcirc':'\u2256','eqcolon':'\u2255','eqsim':'\u2242','eqslantgtr':'\u2A96','eqslantless':'\u2A95','Equal':'\u2A75','equals':'=','EqualTilde':'\u2242','equest':'\u225F','Equilibrium':'\u21CC','equiv':'\u2261','equivDD':'\u2A78','eqvparsl':'\u29E5','erarr':'\u2971','erDot':'\u2253','escr':'\u212F','Escr':'\u2130','esdot':'\u2250','esim':'\u2242','Esim':'\u2A73','eta':'\u03B7','Eta':'\u0397','eth':'\xF0','ETH':'\xD0','euml':'\xEB','Euml':'\xCB','euro':'\u20AC','excl':'!','exist':'\u2203','Exists':'\u2203','expectation':'\u2130','exponentiale':'\u2147','ExponentialE':'\u2147','fallingdotseq':'\u2252','fcy':'\u0444','Fcy':'\u0424','female':'\u2640','ffilig':'\uFB03','fflig':'\uFB00','ffllig':'\uFB04','ffr':'\uD835\uDD23','Ffr':'\uD835\uDD09','filig':'\uFB01','FilledSmallSquare':'\u25FC','FilledVerySmallSquare':'\u25AA','fjlig':'fj','flat':'\u266D','fllig':'\uFB02','fltns':'\u25B1','fnof':'\u0192','fopf':'\uD835\uDD57','Fopf':'\uD835\uDD3D','forall':'\u2200','ForAll':'\u2200','fork':'\u22D4','forkv':'\u2AD9','Fouriertrf':'\u2131','fpartint':'\u2A0D','frac12':'\xBD','frac13':'\u2153','frac14':'\xBC','frac15':'\u2155','frac16':'\u2159','frac18':'\u215B','frac23':'\u2154','frac25':'\u2156','frac34':'\xBE','frac35':'\u2157','frac38':'\u215C','frac45':'\u2158','frac56':'\u215A','frac58':'\u215D','frac78':'\u215E','frasl':'\u2044','frown':'\u2322','fscr':'\uD835\uDCBB','Fscr':'\u2131','gacute':'\u01F5','gamma':'\u03B3','Gamma':'\u0393','gammad':'\u03DD','Gammad':'\u03DC','gap':'\u2A86','gbreve':'\u011F','Gbreve':'\u011E','Gcedil':'\u0122','gcirc':'\u011D','Gcirc':'\u011C','gcy':'\u0433','Gcy':'\u0413','gdot':'\u0121','Gdot':'\u0120','ge':'\u2265','gE':'\u2267','gel':'\u22DB','gEl':'\u2A8C','geq':'\u2265','geqq':'\u2267','geqslant':'\u2A7E','ges':'\u2A7E','gescc':'\u2AA9','gesdot':'\u2A80','gesdoto':'\u2A82','gesdotol':'\u2A84','gesl':'\u22DB\uFE00','gesles':'\u2A94','gfr':'\uD835\uDD24','Gfr':'\uD835\uDD0A','gg':'\u226B','Gg':'\u22D9','ggg':'\u22D9','gimel':'\u2137','gjcy':'\u0453','GJcy':'\u0403','gl':'\u2277','gla':'\u2AA5','glE':'\u2A92','glj':'\u2AA4','gnap':'\u2A8A','gnapprox':'\u2A8A','gne':'\u2A88','gnE':'\u2269','gneq':'\u2A88','gneqq':'\u2269','gnsim':'\u22E7','gopf':'\uD835\uDD58','Gopf':'\uD835\uDD3E','grave':'`','GreaterEqual':'\u2265','GreaterEqualLess':'\u22DB','GreaterFullEqual':'\u2267','GreaterGreater':'\u2AA2','GreaterLess':'\u2277','GreaterSlantEqual':'\u2A7E','GreaterTilde':'\u2273','gscr':'\u210A','Gscr':'\uD835\uDCA2','gsim':'\u2273','gsime':'\u2A8E','gsiml':'\u2A90','gt':'>','Gt':'\u226B','GT':'>','gtcc':'\u2AA7','gtcir':'\u2A7A','gtdot':'\u22D7','gtlPar':'\u2995','gtquest':'\u2A7C','gtrapprox':'\u2A86','gtrarr':'\u2978','gtrdot':'\u22D7','gtreqless':'\u22DB','gtreqqless':'\u2A8C','gtrless':'\u2277','gtrsim':'\u2273','gvertneqq':'\u2269\uFE00','gvnE':'\u2269\uFE00','Hacek':'\u02C7','hairsp':'\u200A','half':'\xBD','hamilt':'\u210B','hardcy':'\u044A','HARDcy':'\u042A','harr':'\u2194','hArr':'\u21D4','harrcir':'\u2948','harrw':'\u21AD','Hat':'^','hbar':'\u210F','hcirc':'\u0125','Hcirc':'\u0124','hearts':'\u2665','heartsuit':'\u2665','hellip':'\u2026','hercon':'\u22B9','hfr':'\uD835\uDD25','Hfr':'\u210C','HilbertSpace':'\u210B','hksearow':'\u2925','hkswarow':'\u2926','hoarr':'\u21FF','homtht':'\u223B','hookleftarrow':'\u21A9','hookrightarrow':'\u21AA','hopf':'\uD835\uDD59','Hopf':'\u210D','horbar':'\u2015','HorizontalLine':'\u2500','hscr':'\uD835\uDCBD','Hscr':'\u210B','hslash':'\u210F','hstrok':'\u0127','Hstrok':'\u0126','HumpDownHump':'\u224E','HumpEqual':'\u224F','hybull':'\u2043','hyphen':'\u2010','iacute':'\xED','Iacute':'\xCD','ic':'\u2063','icirc':'\xEE','Icirc':'\xCE','icy':'\u0438','Icy':'\u0418','Idot':'\u0130','iecy':'\u0435','IEcy':'\u0415','iexcl':'\xA1','iff':'\u21D4','ifr':'\uD835\uDD26','Ifr':'\u2111','igrave':'\xEC','Igrave':'\xCC','ii':'\u2148','iiiint':'\u2A0C','iiint':'\u222D','iinfin':'\u29DC','iiota':'\u2129','ijlig':'\u0133','IJlig':'\u0132','Im':'\u2111','imacr':'\u012B','Imacr':'\u012A','image':'\u2111','ImaginaryI':'\u2148','imagline':'\u2110','imagpart':'\u2111','imath':'\u0131','imof':'\u22B7','imped':'\u01B5','Implies':'\u21D2','in':'\u2208','incare':'\u2105','infin':'\u221E','infintie':'\u29DD','inodot':'\u0131','int':'\u222B','Int':'\u222C','intcal':'\u22BA','integers':'\u2124','Integral':'\u222B','intercal':'\u22BA','Intersection':'\u22C2','intlarhk':'\u2A17','intprod':'\u2A3C','InvisibleComma':'\u2063','InvisibleTimes':'\u2062','iocy':'\u0451','IOcy':'\u0401','iogon':'\u012F','Iogon':'\u012E','iopf':'\uD835\uDD5A','Iopf':'\uD835\uDD40','iota':'\u03B9','Iota':'\u0399','iprod':'\u2A3C','iquest':'\xBF','iscr':'\uD835\uDCBE','Iscr':'\u2110','isin':'\u2208','isindot':'\u22F5','isinE':'\u22F9','isins':'\u22F4','isinsv':'\u22F3','isinv':'\u2208','it':'\u2062','itilde':'\u0129','Itilde':'\u0128','iukcy':'\u0456','Iukcy':'\u0406','iuml':'\xEF','Iuml':'\xCF','jcirc':'\u0135','Jcirc':'\u0134','jcy':'\u0439','Jcy':'\u0419','jfr':'\uD835\uDD27','Jfr':'\uD835\uDD0D','jmath':'\u0237','jopf':'\uD835\uDD5B','Jopf':'\uD835\uDD41','jscr':'\uD835\uDCBF','Jscr':'\uD835\uDCA5','jsercy':'\u0458','Jsercy':'\u0408','jukcy':'\u0454','Jukcy':'\u0404','kappa':'\u03BA','Kappa':'\u039A','kappav':'\u03F0','kcedil':'\u0137','Kcedil':'\u0136','kcy':'\u043A','Kcy':'\u041A','kfr':'\uD835\uDD28','Kfr':'\uD835\uDD0E','kgreen':'\u0138','khcy':'\u0445','KHcy':'\u0425','kjcy':'\u045C','KJcy':'\u040C','kopf':'\uD835\uDD5C','Kopf':'\uD835\uDD42','kscr':'\uD835\uDCC0','Kscr':'\uD835\uDCA6','lAarr':'\u21DA','lacute':'\u013A','Lacute':'\u0139','laemptyv':'\u29B4','lagran':'\u2112','lambda':'\u03BB','Lambda':'\u039B','lang':'\u27E8','Lang':'\u27EA','langd':'\u2991','langle':'\u27E8','lap':'\u2A85','Laplacetrf':'\u2112','laquo':'\xAB','larr':'\u2190','lArr':'\u21D0','Larr':'\u219E','larrb':'\u21E4','larrbfs':'\u291F','larrfs':'\u291D','larrhk':'\u21A9','larrlp':'\u21AB','larrpl':'\u2939','larrsim':'\u2973','larrtl':'\u21A2','lat':'\u2AAB','latail':'\u2919','lAtail':'\u291B','late':'\u2AAD','lates':'\u2AAD\uFE00','lbarr':'\u290C','lBarr':'\u290E','lbbrk':'\u2772','lbrace':'{','lbrack':'[','lbrke':'\u298B','lbrksld':'\u298F','lbrkslu':'\u298D','lcaron':'\u013E','Lcaron':'\u013D','lcedil':'\u013C','Lcedil':'\u013B','lceil':'\u2308','lcub':'{','lcy':'\u043B','Lcy':'\u041B','ldca':'\u2936','ldquo':'\u201C','ldquor':'\u201E','ldrdhar':'\u2967','ldrushar':'\u294B','ldsh':'\u21B2','le':'\u2264','lE':'\u2266','LeftAngleBracket':'\u27E8','leftarrow':'\u2190','Leftarrow':'\u21D0','LeftArrow':'\u2190','LeftArrowBar':'\u21E4','LeftArrowRightArrow':'\u21C6','leftarrowtail':'\u21A2','LeftCeiling':'\u2308','LeftDoubleBracket':'\u27E6','LeftDownTeeVector':'\u2961','LeftDownVector':'\u21C3','LeftDownVectorBar':'\u2959','LeftFloor':'\u230A','leftharpoondown':'\u21BD','leftharpoonup':'\u21BC','leftleftarrows':'\u21C7','leftrightarrow':'\u2194','Leftrightarrow':'\u21D4','LeftRightArrow':'\u2194','leftrightarrows':'\u21C6','leftrightharpoons':'\u21CB','leftrightsquigarrow':'\u21AD','LeftRightVector':'\u294E','LeftTee':'\u22A3','LeftTeeArrow':'\u21A4','LeftTeeVector':'\u295A','leftthreetimes':'\u22CB','LeftTriangle':'\u22B2','LeftTriangleBar':'\u29CF','LeftTriangleEqual':'\u22B4','LeftUpDownVector':'\u2951','LeftUpTeeVector':'\u2960','LeftUpVector':'\u21BF','LeftUpVectorBar':'\u2958','LeftVector':'\u21BC','LeftVectorBar':'\u2952','leg':'\u22DA','lEg':'\u2A8B','leq':'\u2264','leqq':'\u2266','leqslant':'\u2A7D','les':'\u2A7D','lescc':'\u2AA8','lesdot':'\u2A7F','lesdoto':'\u2A81','lesdotor':'\u2A83','lesg':'\u22DA\uFE00','lesges':'\u2A93','lessapprox':'\u2A85','lessdot':'\u22D6','lesseqgtr':'\u22DA','lesseqqgtr':'\u2A8B','LessEqualGreater':'\u22DA','LessFullEqual':'\u2266','LessGreater':'\u2276','lessgtr':'\u2276','LessLess':'\u2AA1','lesssim':'\u2272','LessSlantEqual':'\u2A7D','LessTilde':'\u2272','lfisht':'\u297C','lfloor':'\u230A','lfr':'\uD835\uDD29','Lfr':'\uD835\uDD0F','lg':'\u2276','lgE':'\u2A91','lHar':'\u2962','lhard':'\u21BD','lharu':'\u21BC','lharul':'\u296A','lhblk':'\u2584','ljcy':'\u0459','LJcy':'\u0409','ll':'\u226A','Ll':'\u22D8','llarr':'\u21C7','llcorner':'\u231E','Lleftarrow':'\u21DA','llhard':'\u296B','lltri':'\u25FA','lmidot':'\u0140','Lmidot':'\u013F','lmoust':'\u23B0','lmoustache':'\u23B0','lnap':'\u2A89','lnapprox':'\u2A89','lne':'\u2A87','lnE':'\u2268','lneq':'\u2A87','lneqq':'\u2268','lnsim':'\u22E6','loang':'\u27EC','loarr':'\u21FD','lobrk':'\u27E6','longleftarrow':'\u27F5','Longleftarrow':'\u27F8','LongLeftArrow':'\u27F5','longleftrightarrow':'\u27F7','Longleftrightarrow':'\u27FA','LongLeftRightArrow':'\u27F7','longmapsto':'\u27FC','longrightarrow':'\u27F6','Longrightarrow':'\u27F9','LongRightArrow':'\u27F6','looparrowleft':'\u21AB','looparrowright':'\u21AC','lopar':'\u2985','lopf':'\uD835\uDD5D','Lopf':'\uD835\uDD43','loplus':'\u2A2D','lotimes':'\u2A34','lowast':'\u2217','lowbar':'_','LowerLeftArrow':'\u2199','LowerRightArrow':'\u2198','loz':'\u25CA','lozenge':'\u25CA','lozf':'\u29EB','lpar':'(','lparlt':'\u2993','lrarr':'\u21C6','lrcorner':'\u231F','lrhar':'\u21CB','lrhard':'\u296D','lrm':'\u200E','lrtri':'\u22BF','lsaquo':'\u2039','lscr':'\uD835\uDCC1','Lscr':'\u2112','lsh':'\u21B0','Lsh':'\u21B0','lsim':'\u2272','lsime':'\u2A8D','lsimg':'\u2A8F','lsqb':'[','lsquo':'\u2018','lsquor':'\u201A','lstrok':'\u0142','Lstrok':'\u0141','lt':'<','Lt':'\u226A','LT':'<','ltcc':'\u2AA6','ltcir':'\u2A79','ltdot':'\u22D6','lthree':'\u22CB','ltimes':'\u22C9','ltlarr':'\u2976','ltquest':'\u2A7B','ltri':'\u25C3','ltrie':'\u22B4','ltrif':'\u25C2','ltrPar':'\u2996','lurdshar':'\u294A','luruhar':'\u2966','lvertneqq':'\u2268\uFE00','lvnE':'\u2268\uFE00','macr':'\xAF','male':'\u2642','malt':'\u2720','maltese':'\u2720','map':'\u21A6','Map':'\u2905','mapsto':'\u21A6','mapstodown':'\u21A7','mapstoleft':'\u21A4','mapstoup':'\u21A5','marker':'\u25AE','mcomma':'\u2A29','mcy':'\u043C','Mcy':'\u041C','mdash':'\u2014','mDDot':'\u223A','measuredangle':'\u2221','MediumSpace':'\u205F','Mellintrf':'\u2133','mfr':'\uD835\uDD2A','Mfr':'\uD835\uDD10','mho':'\u2127','micro':'\xB5','mid':'\u2223','midast':'*','midcir':'\u2AF0','middot':'\xB7','minus':'\u2212','minusb':'\u229F','minusd':'\u2238','minusdu':'\u2A2A','MinusPlus':'\u2213','mlcp':'\u2ADB','mldr':'\u2026','mnplus':'\u2213','models':'\u22A7','mopf':'\uD835\uDD5E','Mopf':'\uD835\uDD44','mp':'\u2213','mscr':'\uD835\uDCC2','Mscr':'\u2133','mstpos':'\u223E','mu':'\u03BC','Mu':'\u039C','multimap':'\u22B8','mumap':'\u22B8','nabla':'\u2207','nacute':'\u0144','Nacute':'\u0143','nang':'\u2220\u20D2','nap':'\u2249','napE':'\u2A70\u0338','napid':'\u224B\u0338','napos':'\u0149','napprox':'\u2249','natur':'\u266E','natural':'\u266E','naturals':'\u2115','nbsp':'\xA0','nbump':'\u224E\u0338','nbumpe':'\u224F\u0338','ncap':'\u2A43','ncaron':'\u0148','Ncaron':'\u0147','ncedil':'\u0146','Ncedil':'\u0145','ncong':'\u2247','ncongdot':'\u2A6D\u0338','ncup':'\u2A42','ncy':'\u043D','Ncy':'\u041D','ndash':'\u2013','ne':'\u2260','nearhk':'\u2924','nearr':'\u2197','neArr':'\u21D7','nearrow':'\u2197','nedot':'\u2250\u0338','NegativeMediumSpace':'\u200B','NegativeThickSpace':'\u200B','NegativeThinSpace':'\u200B','NegativeVeryThinSpace':'\u200B','nequiv':'\u2262','nesear':'\u2928','nesim':'\u2242\u0338','NestedGreaterGreater':'\u226B','NestedLessLess':'\u226A','NewLine':'\n','nexist':'\u2204','nexists':'\u2204','nfr':'\uD835\uDD2B','Nfr':'\uD835\uDD11','nge':'\u2271','ngE':'\u2267\u0338','ngeq':'\u2271','ngeqq':'\u2267\u0338','ngeqslant':'\u2A7E\u0338','nges':'\u2A7E\u0338','nGg':'\u22D9\u0338','ngsim':'\u2275','ngt':'\u226F','nGt':'\u226B\u20D2','ngtr':'\u226F','nGtv':'\u226B\u0338','nharr':'\u21AE','nhArr':'\u21CE','nhpar':'\u2AF2','ni':'\u220B','nis':'\u22FC','nisd':'\u22FA','niv':'\u220B','njcy':'\u045A','NJcy':'\u040A','nlarr':'\u219A','nlArr':'\u21CD','nldr':'\u2025','nle':'\u2270','nlE':'\u2266\u0338','nleftarrow':'\u219A','nLeftarrow':'\u21CD','nleftrightarrow':'\u21AE','nLeftrightarrow':'\u21CE','nleq':'\u2270','nleqq':'\u2266\u0338','nleqslant':'\u2A7D\u0338','nles':'\u2A7D\u0338','nless':'\u226E','nLl':'\u22D8\u0338','nlsim':'\u2274','nlt':'\u226E','nLt':'\u226A\u20D2','nltri':'\u22EA','nltrie':'\u22EC','nLtv':'\u226A\u0338','nmid':'\u2224','NoBreak':'\u2060','NonBreakingSpace':'\xA0','nopf':'\uD835\uDD5F','Nopf':'\u2115','not':'\xAC','Not':'\u2AEC','NotCongruent':'\u2262','NotCupCap':'\u226D','NotDoubleVerticalBar':'\u2226','NotElement':'\u2209','NotEqual':'\u2260','NotEqualTilde':'\u2242\u0338','NotExists':'\u2204','NotGreater':'\u226F','NotGreaterEqual':'\u2271','NotGreaterFullEqual':'\u2267\u0338','NotGreaterGreater':'\u226B\u0338','NotGreaterLess':'\u2279','NotGreaterSlantEqual':'\u2A7E\u0338','NotGreaterTilde':'\u2275','NotHumpDownHump':'\u224E\u0338','NotHumpEqual':'\u224F\u0338','notin':'\u2209','notindot':'\u22F5\u0338','notinE':'\u22F9\u0338','notinva':'\u2209','notinvb':'\u22F7','notinvc':'\u22F6','NotLeftTriangle':'\u22EA','NotLeftTriangleBar':'\u29CF\u0338','NotLeftTriangleEqual':'\u22EC','NotLess':'\u226E','NotLessEqual':'\u2270','NotLessGreater':'\u2278','NotLessLess':'\u226A\u0338','NotLessSlantEqual':'\u2A7D\u0338','NotLessTilde':'\u2274','NotNestedGreaterGreater':'\u2AA2\u0338','NotNestedLessLess':'\u2AA1\u0338','notni':'\u220C','notniva':'\u220C','notnivb':'\u22FE','notnivc':'\u22FD','NotPrecedes':'\u2280','NotPrecedesEqual':'\u2AAF\u0338','NotPrecedesSlantEqual':'\u22E0','NotReverseElement':'\u220C','NotRightTriangle':'\u22EB','NotRightTriangleBar':'\u29D0\u0338','NotRightTriangleEqual':'\u22ED','NotSquareSubset':'\u228F\u0338','NotSquareSubsetEqual':'\u22E2','NotSquareSuperset':'\u2290\u0338','NotSquareSupersetEqual':'\u22E3','NotSubset':'\u2282\u20D2','NotSubsetEqual':'\u2288','NotSucceeds':'\u2281','NotSucceedsEqual':'\u2AB0\u0338','NotSucceedsSlantEqual':'\u22E1','NotSucceedsTilde':'\u227F\u0338','NotSuperset':'\u2283\u20D2','NotSupersetEqual':'\u2289','NotTilde':'\u2241','NotTildeEqual':'\u2244','NotTildeFullEqual':'\u2247','NotTildeTilde':'\u2249','NotVerticalBar':'\u2224','npar':'\u2226','nparallel':'\u2226','nparsl':'\u2AFD\u20E5','npart':'\u2202\u0338','npolint':'\u2A14','npr':'\u2280','nprcue':'\u22E0','npre':'\u2AAF\u0338','nprec':'\u2280','npreceq':'\u2AAF\u0338','nrarr':'\u219B','nrArr':'\u21CF','nrarrc':'\u2933\u0338','nrarrw':'\u219D\u0338','nrightarrow':'\u219B','nRightarrow':'\u21CF','nrtri':'\u22EB','nrtrie':'\u22ED','nsc':'\u2281','nsccue':'\u22E1','nsce':'\u2AB0\u0338','nscr':'\uD835\uDCC3','Nscr':'\uD835\uDCA9','nshortmid':'\u2224','nshortparallel':'\u2226','nsim':'\u2241','nsime':'\u2244','nsimeq':'\u2244','nsmid':'\u2224','nspar':'\u2226','nsqsube':'\u22E2','nsqsupe':'\u22E3','nsub':'\u2284','nsube':'\u2288','nsubE':'\u2AC5\u0338','nsubset':'\u2282\u20D2','nsubseteq':'\u2288','nsubseteqq':'\u2AC5\u0338','nsucc':'\u2281','nsucceq':'\u2AB0\u0338','nsup':'\u2285','nsupe':'\u2289','nsupE':'\u2AC6\u0338','nsupset':'\u2283\u20D2','nsupseteq':'\u2289','nsupseteqq':'\u2AC6\u0338','ntgl':'\u2279','ntilde':'\xF1','Ntilde':'\xD1','ntlg':'\u2278','ntriangleleft':'\u22EA','ntrianglelefteq':'\u22EC','ntriangleright':'\u22EB','ntrianglerighteq':'\u22ED','nu':'\u03BD','Nu':'\u039D','num':'#','numero':'\u2116','numsp':'\u2007','nvap':'\u224D\u20D2','nvdash':'\u22AC','nvDash':'\u22AD','nVdash':'\u22AE','nVDash':'\u22AF','nvge':'\u2265\u20D2','nvgt':'>\u20D2','nvHarr':'\u2904','nvinfin':'\u29DE','nvlArr':'\u2902','nvle':'\u2264\u20D2','nvlt':'<\u20D2','nvltrie':'\u22B4\u20D2','nvrArr':'\u2903','nvrtrie':'\u22B5\u20D2','nvsim':'\u223C\u20D2','nwarhk':'\u2923','nwarr':'\u2196','nwArr':'\u21D6','nwarrow':'\u2196','nwnear':'\u2927','oacute':'\xF3','Oacute':'\xD3','oast':'\u229B','ocir':'\u229A','ocirc':'\xF4','Ocirc':'\xD4','ocy':'\u043E','Ocy':'\u041E','odash':'\u229D','odblac':'\u0151','Odblac':'\u0150','odiv':'\u2A38','odot':'\u2299','odsold':'\u29BC','oelig':'\u0153','OElig':'\u0152','ofcir':'\u29BF','ofr':'\uD835\uDD2C','Ofr':'\uD835\uDD12','ogon':'\u02DB','ograve':'\xF2','Ograve':'\xD2','ogt':'\u29C1','ohbar':'\u29B5','ohm':'\u03A9','oint':'\u222E','olarr':'\u21BA','olcir':'\u29BE','olcross':'\u29BB','oline':'\u203E','olt':'\u29C0','omacr':'\u014D','Omacr':'\u014C','omega':'\u03C9','Omega':'\u03A9','omicron':'\u03BF','Omicron':'\u039F','omid':'\u29B6','ominus':'\u2296','oopf':'\uD835\uDD60','Oopf':'\uD835\uDD46','opar':'\u29B7','OpenCurlyDoubleQuote':'\u201C','OpenCurlyQuote':'\u2018','operp':'\u29B9','oplus':'\u2295','or':'\u2228','Or':'\u2A54','orarr':'\u21BB','ord':'\u2A5D','order':'\u2134','orderof':'\u2134','ordf':'\xAA','ordm':'\xBA','origof':'\u22B6','oror':'\u2A56','orslope':'\u2A57','orv':'\u2A5B','oS':'\u24C8','oscr':'\u2134','Oscr':'\uD835\uDCAA','oslash':'\xF8','Oslash':'\xD8','osol':'\u2298','otilde':'\xF5','Otilde':'\xD5','otimes':'\u2297','Otimes':'\u2A37','otimesas':'\u2A36','ouml':'\xF6','Ouml':'\xD6','ovbar':'\u233D','OverBar':'\u203E','OverBrace':'\u23DE','OverBracket':'\u23B4','OverParenthesis':'\u23DC','par':'\u2225','para':'\xB6','parallel':'\u2225','parsim':'\u2AF3','parsl':'\u2AFD','part':'\u2202','PartialD':'\u2202','pcy':'\u043F','Pcy':'\u041F','percnt':'%','period':'.','permil':'\u2030','perp':'\u22A5','pertenk':'\u2031','pfr':'\uD835\uDD2D','Pfr':'\uD835\uDD13','phi':'\u03C6','Phi':'\u03A6','phiv':'\u03D5','phmmat':'\u2133','phone':'\u260E','pi':'\u03C0','Pi':'\u03A0','pitchfork':'\u22D4','piv':'\u03D6','planck':'\u210F','planckh':'\u210E','plankv':'\u210F','plus':'+','plusacir':'\u2A23','plusb':'\u229E','pluscir':'\u2A22','plusdo':'\u2214','plusdu':'\u2A25','pluse':'\u2A72','PlusMinus':'\xB1','plusmn':'\xB1','plussim':'\u2A26','plustwo':'\u2A27','pm':'\xB1','Poincareplane':'\u210C','pointint':'\u2A15','popf':'\uD835\uDD61','Popf':'\u2119','pound':'\xA3','pr':'\u227A','Pr':'\u2ABB','prap':'\u2AB7','prcue':'\u227C','pre':'\u2AAF','prE':'\u2AB3','prec':'\u227A','precapprox':'\u2AB7','preccurlyeq':'\u227C','Precedes':'\u227A','PrecedesEqual':'\u2AAF','PrecedesSlantEqual':'\u227C','PrecedesTilde':'\u227E','preceq':'\u2AAF','precnapprox':'\u2AB9','precneqq':'\u2AB5','precnsim':'\u22E8','precsim':'\u227E','prime':'\u2032','Prime':'\u2033','primes':'\u2119','prnap':'\u2AB9','prnE':'\u2AB5','prnsim':'\u22E8','prod':'\u220F','Product':'\u220F','profalar':'\u232E','profline':'\u2312','profsurf':'\u2313','prop':'\u221D','Proportion':'\u2237','Proportional':'\u221D','propto':'\u221D','prsim':'\u227E','prurel':'\u22B0','pscr':'\uD835\uDCC5','Pscr':'\uD835\uDCAB','psi':'\u03C8','Psi':'\u03A8','puncsp':'\u2008','qfr':'\uD835\uDD2E','Qfr':'\uD835\uDD14','qint':'\u2A0C','qopf':'\uD835\uDD62','Qopf':'\u211A','qprime':'\u2057','qscr':'\uD835\uDCC6','Qscr':'\uD835\uDCAC','quaternions':'\u210D','quatint':'\u2A16','quest':'?','questeq':'\u225F','quot':'"','QUOT':'"','rAarr':'\u21DB','race':'\u223D\u0331','racute':'\u0155','Racute':'\u0154','radic':'\u221A','raemptyv':'\u29B3','rang':'\u27E9','Rang':'\u27EB','rangd':'\u2992','range':'\u29A5','rangle':'\u27E9','raquo':'\xBB','rarr':'\u2192','rArr':'\u21D2','Rarr':'\u21A0','rarrap':'\u2975','rarrb':'\u21E5','rarrbfs':'\u2920','rarrc':'\u2933','rarrfs':'\u291E','rarrhk':'\u21AA','rarrlp':'\u21AC','rarrpl':'\u2945','rarrsim':'\u2974','rarrtl':'\u21A3','Rarrtl':'\u2916','rarrw':'\u219D','ratail':'\u291A','rAtail':'\u291C','ratio':'\u2236','rationals':'\u211A','rbarr':'\u290D','rBarr':'\u290F','RBarr':'\u2910','rbbrk':'\u2773','rbrace':'}','rbrack':']','rbrke':'\u298C','rbrksld':'\u298E','rbrkslu':'\u2990','rcaron':'\u0159','Rcaron':'\u0158','rcedil':'\u0157','Rcedil':'\u0156','rceil':'\u2309','rcub':'}','rcy':'\u0440','Rcy':'\u0420','rdca':'\u2937','rdldhar':'\u2969','rdquo':'\u201D','rdquor':'\u201D','rdsh':'\u21B3','Re':'\u211C','real':'\u211C','realine':'\u211B','realpart':'\u211C','reals':'\u211D','rect':'\u25AD','reg':'\xAE','REG':'\xAE','ReverseElement':'\u220B','ReverseEquilibrium':'\u21CB','ReverseUpEquilibrium':'\u296F','rfisht':'\u297D','rfloor':'\u230B','rfr':'\uD835\uDD2F','Rfr':'\u211C','rHar':'\u2964','rhard':'\u21C1','rharu':'\u21C0','rharul':'\u296C','rho':'\u03C1','Rho':'\u03A1','rhov':'\u03F1','RightAngleBracket':'\u27E9','rightarrow':'\u2192','Rightarrow':'\u21D2','RightArrow':'\u2192','RightArrowBar':'\u21E5','RightArrowLeftArrow':'\u21C4','rightarrowtail':'\u21A3','RightCeiling':'\u2309','RightDoubleBracket':'\u27E7','RightDownTeeVector':'\u295D','RightDownVector':'\u21C2','RightDownVectorBar':'\u2955','RightFloor':'\u230B','rightharpoondown':'\u21C1','rightharpoonup':'\u21C0','rightleftarrows':'\u21C4','rightleftharpoons':'\u21CC','rightrightarrows':'\u21C9','rightsquigarrow':'\u219D','RightTee':'\u22A2','RightTeeArrow':'\u21A6','RightTeeVector':'\u295B','rightthreetimes':'\u22CC','RightTriangle':'\u22B3','RightTriangleBar':'\u29D0','RightTriangleEqual':'\u22B5','RightUpDownVector':'\u294F','RightUpTeeVector':'\u295C','RightUpVector':'\u21BE','RightUpVectorBar':'\u2954','RightVector':'\u21C0','RightVectorBar':'\u2953','ring':'\u02DA','risingdotseq':'\u2253','rlarr':'\u21C4','rlhar':'\u21CC','rlm':'\u200F','rmoust':'\u23B1','rmoustache':'\u23B1','rnmid':'\u2AEE','roang':'\u27ED','roarr':'\u21FE','robrk':'\u27E7','ropar':'\u2986','ropf':'\uD835\uDD63','Ropf':'\u211D','roplus':'\u2A2E','rotimes':'\u2A35','RoundImplies':'\u2970','rpar':')','rpargt':'\u2994','rppolint':'\u2A12','rrarr':'\u21C9','Rrightarrow':'\u21DB','rsaquo':'\u203A','rscr':'\uD835\uDCC7','Rscr':'\u211B','rsh':'\u21B1','Rsh':'\u21B1','rsqb':']','rsquo':'\u2019','rsquor':'\u2019','rthree':'\u22CC','rtimes':'\u22CA','rtri':'\u25B9','rtrie':'\u22B5','rtrif':'\u25B8','rtriltri':'\u29CE','RuleDelayed':'\u29F4','ruluhar':'\u2968','rx':'\u211E','sacute':'\u015B','Sacute':'\u015A','sbquo':'\u201A','sc':'\u227B','Sc':'\u2ABC','scap':'\u2AB8','scaron':'\u0161','Scaron':'\u0160','sccue':'\u227D','sce':'\u2AB0','scE':'\u2AB4','scedil':'\u015F','Scedil':'\u015E','scirc':'\u015D','Scirc':'\u015C','scnap':'\u2ABA','scnE':'\u2AB6','scnsim':'\u22E9','scpolint':'\u2A13','scsim':'\u227F','scy':'\u0441','Scy':'\u0421','sdot':'\u22C5','sdotb':'\u22A1','sdote':'\u2A66','searhk':'\u2925','searr':'\u2198','seArr':'\u21D8','searrow':'\u2198','sect':'\xA7','semi':';','seswar':'\u2929','setminus':'\u2216','setmn':'\u2216','sext':'\u2736','sfr':'\uD835\uDD30','Sfr':'\uD835\uDD16','sfrown':'\u2322','sharp':'\u266F','shchcy':'\u0449','SHCHcy':'\u0429','shcy':'\u0448','SHcy':'\u0428','ShortDownArrow':'\u2193','ShortLeftArrow':'\u2190','shortmid':'\u2223','shortparallel':'\u2225','ShortRightArrow':'\u2192','ShortUpArrow':'\u2191','shy':'\xAD','sigma':'\u03C3','Sigma':'\u03A3','sigmaf':'\u03C2','sigmav':'\u03C2','sim':'\u223C','simdot':'\u2A6A','sime':'\u2243','simeq':'\u2243','simg':'\u2A9E','simgE':'\u2AA0','siml':'\u2A9D','simlE':'\u2A9F','simne':'\u2246','simplus':'\u2A24','simrarr':'\u2972','slarr':'\u2190','SmallCircle':'\u2218','smallsetminus':'\u2216','smashp':'\u2A33','smeparsl':'\u29E4','smid':'\u2223','smile':'\u2323','smt':'\u2AAA','smte':'\u2AAC','smtes':'\u2AAC\uFE00','softcy':'\u044C','SOFTcy':'\u042C','sol':'/','solb':'\u29C4','solbar':'\u233F','sopf':'\uD835\uDD64','Sopf':'\uD835\uDD4A','spades':'\u2660','spadesuit':'\u2660','spar':'\u2225','sqcap':'\u2293','sqcaps':'\u2293\uFE00','sqcup':'\u2294','sqcups':'\u2294\uFE00','Sqrt':'\u221A','sqsub':'\u228F','sqsube':'\u2291','sqsubset':'\u228F','sqsubseteq':'\u2291','sqsup':'\u2290','sqsupe':'\u2292','sqsupset':'\u2290','sqsupseteq':'\u2292','squ':'\u25A1','square':'\u25A1','Square':'\u25A1','SquareIntersection':'\u2293','SquareSubset':'\u228F','SquareSubsetEqual':'\u2291','SquareSuperset':'\u2290','SquareSupersetEqual':'\u2292','SquareUnion':'\u2294','squarf':'\u25AA','squf':'\u25AA','srarr':'\u2192','sscr':'\uD835\uDCC8','Sscr':'\uD835\uDCAE','ssetmn':'\u2216','ssmile':'\u2323','sstarf':'\u22C6','star':'\u2606','Star':'\u22C6','starf':'\u2605','straightepsilon':'\u03F5','straightphi':'\u03D5','strns':'\xAF','sub':'\u2282','Sub':'\u22D0','subdot':'\u2ABD','sube':'\u2286','subE':'\u2AC5','subedot':'\u2AC3','submult':'\u2AC1','subne':'\u228A','subnE':'\u2ACB','subplus':'\u2ABF','subrarr':'\u2979','subset':'\u2282','Subset':'\u22D0','subseteq':'\u2286','subseteqq':'\u2AC5','SubsetEqual':'\u2286','subsetneq':'\u228A','subsetneqq':'\u2ACB','subsim':'\u2AC7','subsub':'\u2AD5','subsup':'\u2AD3','succ':'\u227B','succapprox':'\u2AB8','succcurlyeq':'\u227D','Succeeds':'\u227B','SucceedsEqual':'\u2AB0','SucceedsSlantEqual':'\u227D','SucceedsTilde':'\u227F','succeq':'\u2AB0','succnapprox':'\u2ABA','succneqq':'\u2AB6','succnsim':'\u22E9','succsim':'\u227F','SuchThat':'\u220B','sum':'\u2211','Sum':'\u2211','sung':'\u266A','sup':'\u2283','Sup':'\u22D1','sup1':'\xB9','sup2':'\xB2','sup3':'\xB3','supdot':'\u2ABE','supdsub':'\u2AD8','supe':'\u2287','supE':'\u2AC6','supedot':'\u2AC4','Superset':'\u2283','SupersetEqual':'\u2287','suphsol':'\u27C9','suphsub':'\u2AD7','suplarr':'\u297B','supmult':'\u2AC2','supne':'\u228B','supnE':'\u2ACC','supplus':'\u2AC0','supset':'\u2283','Supset':'\u22D1','supseteq':'\u2287','supseteqq':'\u2AC6','supsetneq':'\u228B','supsetneqq':'\u2ACC','supsim':'\u2AC8','supsub':'\u2AD4','supsup':'\u2AD6','swarhk':'\u2926','swarr':'\u2199','swArr':'\u21D9','swarrow':'\u2199','swnwar':'\u292A','szlig':'\xDF','Tab':'\t','target':'\u2316','tau':'\u03C4','Tau':'\u03A4','tbrk':'\u23B4','tcaron':'\u0165','Tcaron':'\u0164','tcedil':'\u0163','Tcedil':'\u0162','tcy':'\u0442','Tcy':'\u0422','tdot':'\u20DB','telrec':'\u2315','tfr':'\uD835\uDD31','Tfr':'\uD835\uDD17','there4':'\u2234','therefore':'\u2234','Therefore':'\u2234','theta':'\u03B8','Theta':'\u0398','thetasym':'\u03D1','thetav':'\u03D1','thickapprox':'\u2248','thicksim':'\u223C','ThickSpace':'\u205F\u200A','thinsp':'\u2009','ThinSpace':'\u2009','thkap':'\u2248','thksim':'\u223C','thorn':'\xFE','THORN':'\xDE','tilde':'\u02DC','Tilde':'\u223C','TildeEqual':'\u2243','TildeFullEqual':'\u2245','TildeTilde':'\u2248','times':'\xD7','timesb':'\u22A0','timesbar':'\u2A31','timesd':'\u2A30','tint':'\u222D','toea':'\u2928','top':'\u22A4','topbot':'\u2336','topcir':'\u2AF1','topf':'\uD835\uDD65','Topf':'\uD835\uDD4B','topfork':'\u2ADA','tosa':'\u2929','tprime':'\u2034','trade':'\u2122','TRADE':'\u2122','triangle':'\u25B5','triangledown':'\u25BF','triangleleft':'\u25C3','trianglelefteq':'\u22B4','triangleq':'\u225C','triangleright':'\u25B9','trianglerighteq':'\u22B5','tridot':'\u25EC','trie':'\u225C','triminus':'\u2A3A','TripleDot':'\u20DB','triplus':'\u2A39','trisb':'\u29CD','tritime':'\u2A3B','trpezium':'\u23E2','tscr':'\uD835\uDCC9','Tscr':'\uD835\uDCAF','tscy':'\u0446','TScy':'\u0426','tshcy':'\u045B','TSHcy':'\u040B','tstrok':'\u0167','Tstrok':'\u0166','twixt':'\u226C','twoheadleftarrow':'\u219E','twoheadrightarrow':'\u21A0','uacute':'\xFA','Uacute':'\xDA','uarr':'\u2191','uArr':'\u21D1','Uarr':'\u219F','Uarrocir':'\u2949','ubrcy':'\u045E','Ubrcy':'\u040E','ubreve':'\u016D','Ubreve':'\u016C','ucirc':'\xFB','Ucirc':'\xDB','ucy':'\u0443','Ucy':'\u0423','udarr':'\u21C5','udblac':'\u0171','Udblac':'\u0170','udhar':'\u296E','ufisht':'\u297E','ufr':'\uD835\uDD32','Ufr':'\uD835\uDD18','ugrave':'\xF9','Ugrave':'\xD9','uHar':'\u2963','uharl':'\u21BF','uharr':'\u21BE','uhblk':'\u2580','ulcorn':'\u231C','ulcorner':'\u231C','ulcrop':'\u230F','ultri':'\u25F8','umacr':'\u016B','Umacr':'\u016A','uml':'\xA8','UnderBar':'_','UnderBrace':'\u23DF','UnderBracket':'\u23B5','UnderParenthesis':'\u23DD','Union':'\u22C3','UnionPlus':'\u228E','uogon':'\u0173','Uogon':'\u0172','uopf':'\uD835\uDD66','Uopf':'\uD835\uDD4C','uparrow':'\u2191','Uparrow':'\u21D1','UpArrow':'\u2191','UpArrowBar':'\u2912','UpArrowDownArrow':'\u21C5','updownarrow':'\u2195','Updownarrow':'\u21D5','UpDownArrow':'\u2195','UpEquilibrium':'\u296E','upharpoonleft':'\u21BF','upharpoonright':'\u21BE','uplus':'\u228E','UpperLeftArrow':'\u2196','UpperRightArrow':'\u2197','upsi':'\u03C5','Upsi':'\u03D2','upsih':'\u03D2','upsilon':'\u03C5','Upsilon':'\u03A5','UpTee':'\u22A5','UpTeeArrow':'\u21A5','upuparrows':'\u21C8','urcorn':'\u231D','urcorner':'\u231D','urcrop':'\u230E','uring':'\u016F','Uring':'\u016E','urtri':'\u25F9','uscr':'\uD835\uDCCA','Uscr':'\uD835\uDCB0','utdot':'\u22F0','utilde':'\u0169','Utilde':'\u0168','utri':'\u25B5','utrif':'\u25B4','uuarr':'\u21C8','uuml':'\xFC','Uuml':'\xDC','uwangle':'\u29A7','vangrt':'\u299C','varepsilon':'\u03F5','varkappa':'\u03F0','varnothing':'\u2205','varphi':'\u03D5','varpi':'\u03D6','varpropto':'\u221D','varr':'\u2195','vArr':'\u21D5','varrho':'\u03F1','varsigma':'\u03C2','varsubsetneq':'\u228A\uFE00','varsubsetneqq':'\u2ACB\uFE00','varsupsetneq':'\u228B\uFE00','varsupsetneqq':'\u2ACC\uFE00','vartheta':'\u03D1','vartriangleleft':'\u22B2','vartriangleright':'\u22B3','vBar':'\u2AE8','Vbar':'\u2AEB','vBarv':'\u2AE9','vcy':'\u0432','Vcy':'\u0412','vdash':'\u22A2','vDash':'\u22A8','Vdash':'\u22A9','VDash':'\u22AB','Vdashl':'\u2AE6','vee':'\u2228','Vee':'\u22C1','veebar':'\u22BB','veeeq':'\u225A','vellip':'\u22EE','verbar':'|','Verbar':'\u2016','vert':'|','Vert':'\u2016','VerticalBar':'\u2223','VerticalLine':'|','VerticalSeparator':'\u2758','VerticalTilde':'\u2240','VeryThinSpace':'\u200A','vfr':'\uD835\uDD33','Vfr':'\uD835\uDD19','vltri':'\u22B2','vnsub':'\u2282\u20D2','vnsup':'\u2283\u20D2','vopf':'\uD835\uDD67','Vopf':'\uD835\uDD4D','vprop':'\u221D','vrtri':'\u22B3','vscr':'\uD835\uDCCB','Vscr':'\uD835\uDCB1','vsubne':'\u228A\uFE00','vsubnE':'\u2ACB\uFE00','vsupne':'\u228B\uFE00','vsupnE':'\u2ACC\uFE00','Vvdash':'\u22AA','vzigzag':'\u299A','wcirc':'\u0175','Wcirc':'\u0174','wedbar':'\u2A5F','wedge':'\u2227','Wedge':'\u22C0','wedgeq':'\u2259','weierp':'\u2118','wfr':'\uD835\uDD34','Wfr':'\uD835\uDD1A','wopf':'\uD835\uDD68','Wopf':'\uD835\uDD4E','wp':'\u2118','wr':'\u2240','wreath':'\u2240','wscr':'\uD835\uDCCC','Wscr':'\uD835\uDCB2','xcap':'\u22C2','xcirc':'\u25EF','xcup':'\u22C3','xdtri':'\u25BD','xfr':'\uD835\uDD35','Xfr':'\uD835\uDD1B','xharr':'\u27F7','xhArr':'\u27FA','xi':'\u03BE','Xi':'\u039E','xlarr':'\u27F5','xlArr':'\u27F8','xmap':'\u27FC','xnis':'\u22FB','xodot':'\u2A00','xopf':'\uD835\uDD69','Xopf':'\uD835\uDD4F','xoplus':'\u2A01','xotime':'\u2A02','xrarr':'\u27F6','xrArr':'\u27F9','xscr':'\uD835\uDCCD','Xscr':'\uD835\uDCB3','xsqcup':'\u2A06','xuplus':'\u2A04','xutri':'\u25B3','xvee':'\u22C1','xwedge':'\u22C0','yacute':'\xFD','Yacute':'\xDD','yacy':'\u044F','YAcy':'\u042F','ycirc':'\u0177','Ycirc':'\u0176','ycy':'\u044B','Ycy':'\u042B','yen':'\xA5','yfr':'\uD835\uDD36','Yfr':'\uD835\uDD1C','yicy':'\u0457','YIcy':'\u0407','yopf':'\uD835\uDD6A','Yopf':'\uD835\uDD50','yscr':'\uD835\uDCCE','Yscr':'\uD835\uDCB4','yucy':'\u044E','YUcy':'\u042E','yuml':'\xFF','Yuml':'\u0178','zacute':'\u017A','Zacute':'\u0179','zcaron':'\u017E','Zcaron':'\u017D','zcy':'\u0437','Zcy':'\u0417','zdot':'\u017C','Zdot':'\u017B','zeetrf':'\u2128','ZeroWidthSpace':'\u200B','zeta':'\u03B6','Zeta':'\u0396','zfr':'\uD835\uDD37','Zfr':'\u2128','zhcy':'\u0436','ZHcy':'\u0416','zigrarr':'\u21DD','zopf':'\uD835\uDD6B','Zopf':'\u2124','zscr':'\uD835\uDCCF','Zscr':'\uD835\uDCB5','zwj':'\u200D','zwnj':'\u200C'}; var decodeMapLegacy = {'aacute':'\xE1','Aacute':'\xC1','acirc':'\xE2','Acirc':'\xC2','acute':'\xB4','aelig':'\xE6','AElig':'\xC6','agrave':'\xE0','Agrave':'\xC0','amp':'&','AMP':'&','aring':'\xE5','Aring':'\xC5','atilde':'\xE3','Atilde':'\xC3','auml':'\xE4','Auml':'\xC4','brvbar':'\xA6','ccedil':'\xE7','Ccedil':'\xC7','cedil':'\xB8','cent':'\xA2','copy':'\xA9','COPY':'\xA9','curren':'\xA4','deg':'\xB0','divide':'\xF7','eacute':'\xE9','Eacute':'\xC9','ecirc':'\xEA','Ecirc':'\xCA','egrave':'\xE8','Egrave':'\xC8','eth':'\xF0','ETH':'\xD0','euml':'\xEB','Euml':'\xCB','frac12':'\xBD','frac14':'\xBC','frac34':'\xBE','gt':'>','GT':'>','iacute':'\xED','Iacute':'\xCD','icirc':'\xEE','Icirc':'\xCE','iexcl':'\xA1','igrave':'\xEC','Igrave':'\xCC','iquest':'\xBF','iuml':'\xEF','Iuml':'\xCF','laquo':'\xAB','lt':'<','LT':'<','macr':'\xAF','micro':'\xB5','middot':'\xB7','nbsp':'\xA0','not':'\xAC','ntilde':'\xF1','Ntilde':'\xD1','oacute':'\xF3','Oacute':'\xD3','ocirc':'\xF4','Ocirc':'\xD4','ograve':'\xF2','Ograve':'\xD2','ordf':'\xAA','ordm':'\xBA','oslash':'\xF8','Oslash':'\xD8','otilde':'\xF5','Otilde':'\xD5','ouml':'\xF6','Ouml':'\xD6','para':'\xB6','plusmn':'\xB1','pound':'\xA3','quot':'"','QUOT':'"','raquo':'\xBB','reg':'\xAE','REG':'\xAE','sect':'\xA7','shy':'\xAD','sup1':'\xB9','sup2':'\xB2','sup3':'\xB3','szlig':'\xDF','thorn':'\xFE','THORN':'\xDE','times':'\xD7','uacute':'\xFA','Uacute':'\xDA','ucirc':'\xFB','Ucirc':'\xDB','ugrave':'\xF9','Ugrave':'\xD9','uml':'\xA8','uuml':'\xFC','Uuml':'\xDC','yacute':'\xFD','Yacute':'\xDD','yen':'\xA5','yuml':'\xFF'}; var decodeMapNumeric = {'0':'\uFFFD','128':'\u20AC','130':'\u201A','131':'\u0192','132':'\u201E','133':'\u2026','134':'\u2020','135':'\u2021','136':'\u02C6','137':'\u2030','138':'\u0160','139':'\u2039','140':'\u0152','142':'\u017D','145':'\u2018','146':'\u2019','147':'\u201C','148':'\u201D','149':'\u2022','150':'\u2013','151':'\u2014','152':'\u02DC','153':'\u2122','154':'\u0161','155':'\u203A','156':'\u0153','158':'\u017E','159':'\u0178'}; @@ -229,69 +229,72 @@ if (strict && regexInvalidEntity.test(html)) { parseError('malformed character reference'); } - return html.replace(regexDecode, function($0, $1, $2, $3, $4, $5, $6, $7) { + return html.replace(regexDecode, function($0, $1, $2, $3, $4, $5, $6, $7, $8) { var codePoint; var semicolon; var decDigits; var hexDigits; var reference; var next; + if ($1) { + reference = $1; + // Note: there is no need to check `has(decodeMap, reference)`. + return decodeMap[reference]; + } + + if ($2) { + // Decode named character references without trailing `;`, e.g. `&`. + // This is only a parse error if it gets converted to `&`, or if it is + // followed by `=` in an attribute context. + reference = $2; + next = $3; + if (next && options.isAttributeValue) { + if (strict && next == '=') { + parseError('`&` did not start a character reference'); + } + return $0; + } else { + if (strict) { + parseError( + 'named character reference was not terminated by a semicolon' + ); + } + // Note: there is no need to check `has(decodeMapLegacy, reference)`. + return decodeMapLegacy[reference] + (next || ''); + } + } + + if ($4) { // Decode decimal escapes, e.g. `𝌆`. - decDigits = $1; - semicolon = $2; + decDigits = $4; + semicolon = $5; if (strict && !semicolon) { parseError('character reference was not terminated by a semicolon'); } codePoint = parseInt(decDigits, 10); return codePointToSymbol(codePoint, strict); } - if ($3) { + + if ($6) { // Decode hexadecimal escapes, e.g. `𝌆`. - hexDigits = $3; - semicolon = $4; + hexDigits = $6; + semicolon = $7; if (strict && !semicolon) { parseError('character reference was not terminated by a semicolon'); } codePoint = parseInt(hexDigits, 16); return codePointToSymbol(codePoint, strict); } - if ($5) { - // Decode named character references with trailing `;`, e.g. `©`. - reference = $5; - if (has(decodeMap, reference)) { - return decodeMap[reference]; - } else { - // Ambiguous ampersand. https://mths.be/notes/ambiguous-ampersands - if (strict) { - parseError( - 'named character reference was not terminated by a semicolon' - ); - } - return $0; - } - } - // If we’re still here, it’s a legacy reference for sure. No need for an - // extra `if` check. - // Decode named character references without trailing `;`, e.g. `&` - // This is only a parse error if it gets converted to `&`, or if it is - // followed by `=` in an attribute context. - reference = $6; - next = $7; - if (next && options.isAttributeValue) { - if (strict && next == '=') { - parseError('`&` did not start a character reference'); - } - return $0; - } else { - if (strict) { - parseError( - 'named character reference was not terminated by a semicolon' - ); - } - // Note: there is no need to check `has(decodeMapLegacy, reference)`. - return decodeMapLegacy[reference] + (next || ''); + + // If we’re still here, `if ($7)` is implied; it’s an ambiguous + // ampersand for sure. https://mths.be/notes/ambiguous-ampersands + if (strict) { + parseError( + 'named character reference was not terminated by a semicolon' + ); } + return $0; }); }; // Expose default options (so they can be overridden globally). @@ -310,7 +313,7 @@ /*--------------------------------------------------------------------------*/ var he = { - 'version': '1.1.1', + 'version': '1.2.0', 'encode': encode, 'decode': decode, 'escape': escape, diff --git a/js/jquery.fontselect.js b/js/jquery.fontselect.js index d9658e1..6cf192f 100644 --- a/js/jquery.fontselect.js +++ b/js/jquery.fontselect.js @@ -9,7 +9,7 @@ * * Modified by John Romano D'Orazio, https://www.johnromanodorazio.com * Modification Date June 12, 2017 - * + * Modification Date March 25, 2020 * * */ @@ -313,7 +313,8 @@ } } // END IF FONT this.$original.data('fonttype',fontType); - //console.log('>>>> setting this.$original.data("fonttype") to:' +fontType); + this.$original.attr('data-fonttype',fontType); + console.log('>>>> setting this.$original.data("fonttype") to:' +fontType); this.updateSelected(); //this will download the full font set for google fonts, which is useful so that preview text will be shown in this font this.getVisibleFonts(); this.bindEvents(); @@ -352,7 +353,8 @@ var font = $('li.active', this.$results).data('value'); var fontType = $('li.active', this.$results).data('fonttype'); this.$original.data('fonttype',fontType); - //console.log('selectFont >> this.$original.data("fonttype") = ' + this.$original.data('fonttype')); + this.$original.attr('data-fonttype',fontType); + console.log('selectFont >> this.$original.data("fonttype") = ' + this.$original.data('fonttype')); this.$original.val(font).change(); this.updateSelected(); this.toggleDrop(); @@ -389,7 +391,7 @@ var font = this.$original.val(); var fontType = this.$original.data('fonttype'); - //console.log('updateSelected >> this.$original.data("fonttype") = ' + fontType); + console.log('updateSelected >> this.$original.data("fonttype") = ' + fontType); if(fontType == 'googlefont'){ $('span', this.$element).text(this.toReadable(font)).css(this.toStyle(font)); var link = this.options.api + font; @@ -417,8 +419,15 @@ this.$drop = $('
', {'class': 'fs-drop'}); this.$results = $('
    ', {'class': 'fs-results'}); this.$original.after(this.$element.append(this.$select.append(this.$arrow)).append(this.$drop)); - this.$drop.append(this.$results.append(this.fontsAsHtml())).hide(); - //console.log('setupHtml END'); + this.$fontsAsHtml = $(this.fontsAsHtml()); + this.$drop.append(this.$results.append(this.$fontsAsHtml)).hide(); + + this.$prefetch = $('
    ', {'class': 'font-select-prefetch'}); + this.$results_prefetch = this.$results.clone(); + this.$fontsAsHtml_prefetch = this.$fontsAsHtml.clone(); + this.$prefetch.append(this.$results_prefetch.append(this.$fontsAsHtml_prefetch)); + jQuery('body').append(this.$prefetch); + //console.log('setupHtml END'); }; Fontselect.prototype.fontsAsHtml = function(){ @@ -516,11 +525,18 @@ Fontselect.prototype.addFontLink = function(font){ - var link = this.options.api + font + '&text=' + encodeURIComponent(this.toReadable(font).replace(/\s+/g, '')); - - if ($("link[href*='" + font + "']").length === 0){ - $('link:last').after(''); - } + //var link = this.options.api + font + '&text=' + encodeURIComponent(this.toReadable(font).replace(/\s+/g, '')); + /* + var fontfilename = encodeURIComponent(this.toReadable(font).replace(/\s+/g, '')); + var link = '/css/gfonts_preview/' + fontfilename + '.css'; + if(typeof FontSelect_Control !== 'undefined'){ + if(FontSelect_Control.hasOwnProperty('pluginUrl') && FontSelect_Control.pluginUrl != ''){ + if ($("link[href='" + FontSelect_Control.pluginUrl + link + "']").length === 0){ + $('link:last').after(''); + } + } + } + */ }; return Fontselect; @@ -530,7 +546,36 @@ if (options) { $.extend( settings, options ); } - return new Fontselect(this, settings, $.fontselect.google_fonts); + if(typeof FontSelect_Control !== 'undefined'){ + if(FontSelect_Control.hasOwnProperty('bibleget_settings') && FontSelect_Control.bibleget_settings.hasOwnProperty('googlefontsapi_key') && FontSelect_Control.bibleget_settings.googlefontsapi_key != ''){ + settings.api = 'https://fonts.googleapis.com/css2?key='+FontSelect_Control.bibleget_settings.googlefontsapi_key+'&family='; + var $ths = this; + jQuery.ajax({ + url: 'https://www.googleapis.com/webfonts/v1/webfonts', + data: {'key':FontSelect_Control.bibleget_settings.googlefontsapi_key}, + dataType: 'json', + type: 'get', + success: function(data){ + //console.log(data); + var webfontList = data.items; + $.fontselect.google_fonts = []; + for(var it = 0; it < webfontList.length; it++){ + $.fontselect.google_fonts[it] = webfontList[it].family.replace(/ /g, "+"); + } + //console.log('new fontselect.google_fonts:'); + //console.log($.fontselect.google_fonts); + return new Fontselect($ths, settings, $.fontselect.google_fonts); + }, + error: function(jqXHR, textStatus, errorThrown){ + console.log('error retrieving google fonts list :: '+textStatus+': '+errorThrown); + } + }); + } + //console.log(bibleget_settings); + } + else { + return new Fontselect(this, settings, $.fontselect.google_fonts); + } }); }; diff --git a/js/shortcode.js b/js/shortcode.js index 55e2c9f..41f4da8 100644 --- a/js/shortcode.js +++ b/js/shortcode.js @@ -8,7 +8,11 @@ autoOpen: false, width: ($(window).width() * 0.8), maxHeight: ($(window).height() * 0.8), - title: $(this).text() + title: $(this).text(), + create: function () { + // style fix for WordPress admin + $('.ui-dialog-titlebar-close').addClass('ui-button'); + } }); $(this).click(function(){ diff --git a/js/theme-customizer.js b/js/theme-customizer.js index 30c4f7d..32b5026 100644 --- a/js/theme-customizer.js +++ b/js/theme-customizer.js @@ -11,6 +11,7 @@ wp.customize( 'bibleget_fontfamily', function( value ) { value.bind( function( newval ) { + var fontType = parent.jQuery('#bibleget-googlefonts').attr('data-fonttype'); //alert(newval); //console.log('wp.customize bibleget_fontfamily BEGIN'); //console.log(newval); @@ -18,13 +19,15 @@ font = font.split(':'); //console.log(font); //console.log('wp.customize bibleget_fontfamily END'); - var link = 'https://fonts.googleapis.com/css?family=' + newval; - if ($("link[href*='" + font + "']").length > 0){ - $("link[href*='" + font + "']").attr('href',link) - } - else{ - $('link:last').after(''); - } + if(fontType == 'googlefont'){ + var link = 'https://fonts.googleapis.com/css?family=' + newval; + if ($("link[href*='" + font + "']").length > 0){ + $("link[href*='" + font + "']").attr('href',link) + } + else{ + $('link:last').after(''); + } + } $('div.results').css('font-family', font[0] ); } ); } ); diff --git a/options.php b/options.php index 3090638..30c2d1c 100644 --- a/options.php +++ b/options.php @@ -1,4 +1,6 @@ versionsbylang = array(); $this->versionlangs = array(); $this->countversionsbylang = 0; $this->countversionlangs = 0; $this->biblebookslangs = array(); - + $this->gfonts_weblist = new stdClass(); + $this->gfonts_dir = ""; + $this->options = get_option( 'bibleget_settings' ); + $this->gfontsAPIkey = ""; + $this->gfontsAPIkeyCheckResult = false; + $this->gfontsAPIresponseJSON = new stdClass(); + $this->gfontsAPI_errors = array(); + add_action( 'admin_menu', array( $this, 'add_plugin_page' ) ); + add_action( 'admin_init', array( $this, 'register_settings' ) ); + + //if I understand correctly, ajax function callbacks need to be registered even before enqueue_scripts + //so let't pull it out of admin_print_scripts and place it here even before enqueue_scripts is called + //this will change the transient set, it cannot happen in gfontsAPIkeyCheck which is called on any admin interface + //we will have to leave the transient set to admin_print_scripts + switch($this->gfontsAPIkeyCheck()){ //can either check directly the return value of the script as we are doing here, or check the value as stored in the class private variable $this->gfontsAPIkeyCheckResult + case false: + //the gfontsAPIkey is not set, so let's just not do anything, ok + break; + case "SUCCESS": + //the gfontsAPIkey is set, and transient has been set and successful curl call made to the google fonts API + //error_log('CURRENT VALUE OF $this->gfontsAPIresponseJSON:'); + //error_log(print_r($this->gfontsAPIresponseJSON,true)); + //error_log('AJAX ACTION NOW BEING ADDED WITH THESE VALUES'); + add_action( "wp_ajax_store_gfonts_preview", array( $this, 'store_gfonts_preview' ) ); + //enqueue and localize will be done in enqueue_scripts + + // Include CSS minifier by matthiasmullie + $minifierpath = WP_PLUGIN_DIR."/bibleget-io/minifier"; + require_once $minifierpath . '/minify/src/Minify.php'; + require_once $minifierpath . '/minify/src/CSS.php'; + require_once $minifierpath . '/minify/src/JS.php'; + require_once $minifierpath . '/minify/src/Exception.php'; + require_once $minifierpath . '/minify/src/Exceptions/BasicException.php'; + require_once $minifierpath . '/minify/src/Exceptions/FileImportException.php'; + require_once $minifierpath . '/minify/src/Exceptions/IOException.php'; + require_once $minifierpath . '/path-converter/src/ConverterInterface.php'; + require_once $minifierpath . '/path-converter/src/Converter.php'; + break; + case "CURL_ERROR": + break; + case "JSON_ERROR": + break; + case "REQUEST_NOT_SENT": + break; + } + + add_action('admin_enqueue_scripts', array( $this, 'admin_print_styles') ); + add_action('admin_enqueue_scripts', array( $this, 'admin_print_scripts') ); + add_action('load-'.$this->options_page_hook, array( $this, 'bibleget_plugin_settings_save') ); + } /** @@ -33,7 +88,7 @@ public function __construct() */ public function add_plugin_page() { - // This page will be under "Settings" + // This page will be under "Settings" $this->options_page_hook = add_options_page( __('BibleGet I/O Settings',"bibleget-io"), // $page_title 'BibleGet I/O', // $menu_title @@ -41,13 +96,120 @@ public function add_plugin_page() 'bibleget-settings-admin', // $menu_slug (Page ID) array( $this, 'create_admin_page' ) // Callback Function ); - - add_action('admin_enqueue_scripts', array( $this, 'admin_print_styles') ); - add_action('admin_enqueue_scripts', array( $this, 'admin_print_scripts') ); - add_action('load-'.$this->options_page_hook, array( $this, 'do_on_my_plugin_settings_save') ); - - //start populating as soon as possible - $this->getVersionsByLang(); + } + + /** + * Register and add settings + */ + public function register_settings() + { + + register_setting( + 'bibleget_settings_options', // Option group + 'bibleget_settings', // Option name + array( $this, 'sanitize' ) // Sanitize + ); + + add_settings_section( + 'bibleget_settings_section2', // ID + __('Preferences Settings',"bibleget-io"), // Title + array( $this, 'print_section_info2' ), // Callback + 'bibleget-settings-admin' // Page + ); + + add_settings_field( + 'favorite_version', + __('Preferred version or versions (when not indicated in shortcode)',"bibleget-io"), + array( $this, 'favorite_version_callback' ), + 'bibleget-settings-admin', + 'bibleget_settings_section2' + ); + + add_settings_field( + 'googlefontsapi_key', + __('Google Fonts API key (for updated font list)',"bibleget-io"), + array( $this, 'googlefontsapikey_callback' ), + 'bibleget-settings-admin', + 'bibleget_settings_section2' + ); + + } + + public function admin_print_styles($hook) + { + if($hook == 'settings_page_bibleget-settings-admin'){ + wp_enqueue_style( 'admin-css', plugins_url('css/admin.css', __FILE__) ); + } + } + + public function admin_print_scripts($hook) + { + //echo "
    $hook
    "; + if($hook != 'settings_page_bibleget-settings-admin'){ + return; + } + + wp_register_script( 'admin-js', plugins_url('js/admin.js', __FILE__), array('jquery') ); + $thisoptions = get_option( 'bibleget_settings' ); + $myoptions = array(); + if($thisoptions){ + foreach($thisoptions as $key => $option){ + $myoptions[$key] = esc_attr($option); + } + } + $obj = array("options" => $myoptions,'ajax_url' => admin_url( 'admin-ajax.php' ),'ajax_nonce' => wp_create_nonce( "bibleget-data" )); + wp_localize_script( 'admin-js', 'bibleGetOptionsFromServer', $obj ); + wp_enqueue_script( 'admin-js' ); + + if($this->gfontsAPIkeyCheckResult == "SUCCESS"){ + //We only want the transient to be set from the bibleget settings page, so we wait until now + // instead of doing it in the gfontsAPIkeyCheck (which is called on any admin interface) + set_transient ( md5 ( $this->options['googlefontsapi_key'] ), $this->gfontsAPIkeyCheckResult, 90 * 24 * HOUR_IN_SECONDS ); // 90 giorni + + $this->gfonts_dir = WP_PLUGIN_DIR."/bibleget-io/gfonts_preview/"; + + $access_type = get_filesystem_method(); + $plugin_path = ""; + if($access_type === 'direct'){ + $creds = request_filesystem_credentials(site_url() . '/wp-admin/', '', false, false, array()); + /* initialize the API */ + if ( WP_Filesystem($creds) ) { + global $wp_filesystem; + $plugin_path = str_replace(ABSPATH, $wp_filesystem->abspath(), plugin_dir_path( __FILE__ )); + if(!$wp_filesystem->is_dir($plugin_path . 'gfonts_preview/')){ + /* directory didn't exist, so let's create it */ + $wp_filesystem->mkdir($plugin_path . 'gfonts_preview/'); + } + if(!$wp_filesystem->is_dir($plugin_path . 'css/gfonts_preview/')){ + /* directory didn't exist, so let's create it */ + $wp_filesystem->mkdir($plugin_path . 'css/gfonts_preview/'); + } + + //let's also cache the results from the Google Fonts API in a local file so we don't have to keep calling + $wp_filesystem->put_contents( + $plugin_path . 'gfonts_preview/gfontsWeblist.json', + json_encode($this->gfonts_weblist), + FS_CHMOD_FILE // predefined mode settings for WP files + ); + + } + else{ + $this->gfontsAPI_errors[] = "Could not initialize wordpress filesystem with these credentials"; + } + } + else{ + $this->gfontsAPI_errors[] = "You do not have direct access permissions to the wordpress filesystem"; + } + + wp_enqueue_script( 'jquery-ui-progressbar' ); + if(!wp_style_is('jquery-ui-css','registered') || !wp_style_is('jquery-ui-css','enqueued')){ + wp_enqueue_style('jquery-ui-css', + '//ajax.googleapis.com/ajax/libs/jqueryui/' . wp_scripts()->registered['jquery-ui-core']->ver . '/themes/smoothness/jquery-ui.css'); + } + $storeGfontsArr = array("job" => array( "gfontsPreviewJob" => (bool) true, "gfontsNonce" => wp_create_nonce("store_gfonts_preview_nonce"),'ajax_url' => admin_url( 'admin-ajax.php' ), 'gfontsWeblist' => $this->gfonts_weblist)); + wp_localize_script( 'admin-js', 'gfontsBatch', $storeGfontsArr); + } + } /** @@ -55,32 +217,34 @@ public function add_plugin_page() */ public function create_admin_page() { + + //start populating as soon as possible + $this->getVersionsByLang(); + //write_log("creating admin page\n"); // Set class property - $this->options = get_option( 'bibleget_settings' ); - + ?>
    - -

    +

    match group name in register_setting() do_settings_sections( 'bibleget-settings-admin' ); // $page_slug - submit_button(); + submit_button(); ?>
    - +
    -
    +

      -
    1. countversionsbylang<1 || $this->countversionlangs<1){ echo "Seems like the version info was not yet initialized. Now attempting to initialize..."; $this->getVersionsByLang(); @@ -100,14 +264,14 @@ public function create_admin_page() foreach($this->versionsbylang[$lang] as $abbr => $value){ echo '
    2. '.(++$cc).') '.$abbr.' — '.$value["fullname"].' ('.$value["year"].')
    3. '; } - echo '
'; + echo ''; } - echo ""; + echo "
"; ?> -
  • biblebookslangs).$b2; /* translators: please do not change the placeholders %s, they will be substituted dynamically by values in the script. See http://php.net/printf. */ - printf(__("The BibleGet I/O engine currently recognizes the names of the books of the Bible in %s different languages:","bibleget-io"),$string3); + printf(__("The BibleGet I/O engine currently recognizes the names of the books of the Bible in %s different languages:","bibleget-io"),$string3); echo "
    "; echo "
    ".implode(", ",$this->biblebookslangs)."
    "; ?>
  • @@ -119,17 +283,17 @@ public function create_admin_page()

    - =')) { $locale_lang = explode("_",$locale)[0]; //variable dereferencing available only since PHP 5.4 } else{ list($locale_lang,$locale_country) = explode("_",$locale); //lower than PHP 5.4 } - + } else { $locale_lang = $locale; } if(file_exists(plugins_url( 'images/btn_donateCC_LG'.($locale_lang ? '-'.$locale_lang : '').'.gif', __FILE__ )) ){ @@ -137,43 +301,14 @@ public function create_admin_page() } else $donate_img = plugins_url( 'images/btn_donateCC_LG.gif', __FILE__ ); ?> -
    +
    x -
    +
    biblebookslangs,$lang); } - + //write_log($this->biblebookslangs); - + if(extension_loaded('intl') === true){ collator_asort(collator_create('root'), $this->biblebookslangs); }else{ array_multisort(array_map('bibleGetSortify', $this->biblebookslangs), $this->biblebookslangs); } - //write_log($this->biblebookslangs); - + //write_log($this->biblebookslangs); + $versions = get_option("bibleget_versions",array()); //theoretically should be an array $versionsbylang = array(); $langs = array(); @@ -261,7 +398,7 @@ public function getVersionsByLang() } } $this->versionsbylang = $versionsbylang; - + //count total languages and total versions $this->countversionlangs = count($versionsbylang); $counter = 0; @@ -270,7 +407,7 @@ public function getVersionsByLang() $counter+=count($versionsbylang[$lang]); } $this->countversionsbylang = $counter; - + if(extension_loaded('intl') === true){ collator_asort(collator_create('root'), $langs); }else{ @@ -278,28 +415,28 @@ public function getVersionsByLang() } $this->versionlangs = $langs; - + } - + public function favorite_version_callback() { //double check to see if the values have been set if($this->countversionsbylang<1 || $this->countversionlangs<1){ $this->getVersionsByLang(); } - + $counter = ($this->countversionsbylang + $this->countversionlangs); - + $selected = array(); if(isset( $this->options['favorite_version'] ) && $this->options['favorite_version']){ $selected = explode(",",$this->options['favorite_version']); } $size = $counter<10 ? $counter : 10; echo ''; echo ''; } - - public function admin_print_styles($hook) - { - if($hook == 'settings_page_bibleget-settings-admin'){ - wp_enqueue_style( 'admin-css', plugins_url('css/admin.css', __FILE__) ); + + public function googlefontsapikey_callback(){ + + echo ''; + if($this->gfontsAPIkeyCheckResult){ + switch ($this->gfontsAPIkeyCheckResult){ + case "SUCCESS": + echo 'SUCCESS'; + break; + case "CURL_ERROR": + echo 'CURL ERROR WHEN SENDING REQUEST'; + foreach($this->gfontsAPI_errors as $er){ + echo '
    ' . $er . ''; + } + break; + case "JSON_ERROR": + echo 'NO VALID JSON RESPONSE'; + break; + case "REQUEST_NOT_SENT": + echo 'SERVER UNABLE TO MAKE REQUESTS'; + break; + } } + echo '
    ' . __("If you would like to use a Google Font that is not already included in the list of available fonts, you should use a Google Fonts API key.' . + ' If you do not yet have a Google Fonts API Key, you can get one here", "bibleget-io") . ': https://developers.google.com/fonts/docs/developer_api' . + ' If you choose to apply restrictions to your api key, choose "IP Addresses (web servers, cron jobs etc)" and if you restrict to specific IP addresses be sure to include any and all interface network addresses that your server may use;' . + ' specifically the ip address found in the $_SERVER['SERVER_ADDR'] variable (it may take a few minutes to be effective).' . + ' A successful key will be cached and retested every 3 months. Please note that this may have a little bit of an impact on the loading performance of your Wordpress Customizer. If you notice that it becomes too sluggish, you had best leave this field empty.'; } - public function admin_print_scripts($hook) - { - //echo "
    $hook
    "; - if($hook != 'settings_page_bibleget-settings-admin'){ - return; - } - - wp_register_script( 'admin-js', plugins_url('js/admin.js', __FILE__), array('jquery') ); - $thisoptions = get_option( 'bibleget_settings' ); - $myoptions = array(); - if($thisoptions){ - foreach($thisoptions as $key => $option){ - $myoptions[$key] = esc_attr($option); - } + public function gfontsAPIkeyCheck(){ + $result = false; + $this->gfontsAPI_errors = array(); //we want to start with a clean slate + + if(isset( $this->options['googlefontsapi_key'] ) && $this->options['googlefontsapi_key'] != ""){ + $this->gfontsAPIkey = $this->options['googlefontsapi_key']; + //has this key been tested in the past 3 months at least? + if(false === ($result = get_transient ( md5 ( $this->options['googlefontsapi_key'] ) )) ){ + + //We will make a secure connection to the Google Fonts API endpoint + $curl_version = curl_version(); + $ssl_version = str_replace('OpenSSL/','',$curl_version['ssl_version']); + if( version_compare( $curl_version['version'], '7.34.0', '>=') && version_compare( $ssl_version, '1.0.1', '>=' ) ){ + //we should be good to go for secure SSL communication supporting TLSv1_2 + $ch = curl_init ( "https://www.googleapis.com/webfonts/v1/webfonts?key=" . $this->options['googlefontsapi_key']); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2 ); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE ); + curl_setopt($ch, CURLOPT_INTERFACE, $_SERVER['SERVER_ADDR']); + if (ini_get ( 'safe_mode' ) || ini_get ( 'open_basedir' )) { + // safe mode is on, we can't use some settings + } else { + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE ); + curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE ); + } + $response = curl_exec ( $ch ); + $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($response && ! curl_errno ( $ch ) && $status == 200) { + //let's see what was returned, and if it's what we're looking for + $json_response = json_decode($response); + if ($json_response !== null && json_last_error() === JSON_ERROR_NONE) { + //So far so good, let's keep these results for other functions to access + $this->gfontsAPIresponseJSON = $json_response; + + if(property_exists($json_response,"kind") && $json_response->kind == "webfonts#webfontList" && property_exists($json_response,"items") ){ + $this->gfonts_weblist = $json_response; + $result = "SUCCESS"; + } + } + else{ + $result = "JSON_ERROR"; + } + } else { + if(!$response){ + $this->gfontsAPI_errors[] = "Response from curl request is false"; + } + if(curl_errno($ch)){ + $this->gfontsAPI_errors[] = curl_error($ch); + } + if($status != 200){ + $this->gfontsAPI_errors[] = "Status = " . $status; + } + $result = "CURL_ERROR"; + } + curl_close ( $ch ); + } + else{ + //we're not going anywhere here, can't make a secure connection to the google fonts api + $result = "REQUEST_NOT_SENT"; + } + + + } + else{ + //we have a previously saved api key which has been tested + //$result is not false + } } - $obj = array("options" => $myoptions,'ajax_url' => admin_url( 'admin-ajax.php' ),'ajax_nonce' => wp_create_nonce( "bibleget-data" )); - wp_localize_script( 'admin-js', 'obj', $obj ); - wp_enqueue_script( 'admin-js' ); + else{ + //we don't have a previously saved api key, but really who cares + } + + $this->gfontsAPIkeyCheckResult = $result; + return $result; + } + + public function store_gfonts_preview(){ + check_ajax_referer( 'store_gfonts_preview_nonce', 'security', TRUE ); //no need for an "if", it will die if not valid + //$this->gfonts_weblist contains $json_response, no need to retrieve from the javascript ajax data! + $returnInfo = new stdClass(); + $thisfamily = ""; + $familyurlname = ""; + $familyfilename = ""; + $errorinfo = array(); + $gfontsDir = WP_PLUGIN_DIR."/bibleget-io/gfonts_preview/"; + $gfontsWeblist = new stdClass(); + + if(file_exists($gfontsDir."gfontsWeblist.json")){ + $gfontsWeblistFile = file_get_contents($gfontsDir."gfontsWeblist.json"); + $gfontsWeblist = json_decode($gfontsWeblistFile); + } + if(isset($_POST["gfontsCount"],$_POST["batchLimit"],$_POST["startIdx"],$_POST["lastBatchLimit"],$_POST["numRuns"],$_POST["currentRun"]) && property_exists($gfontsWeblist,"items") ){ + $gfontsCount = intval($_POST["gfontsCount"]); + $batchLimit = intval($_POST["batchLimit"]); + $startIdx = intval($_POST["startIdx"]); + $lastBatchLimit = intval($_POST["lastBatchLimit"]); + $numRuns = intval($_POST["numRuns"]); + $currentRun = intval($_POST["currentRun"]); + //$errorinfo[] = "POST data received: ".print_r($_POST,true); + //$gfontsWeblist = (is_object($_POST["gfontsWeblist"])) ? $_POST["gfontsWeblist"] : ( is_array($_POST["gfontsWeblist"]) ? (object)$_POST["gfontsWeblist"] : ( is_string($_POST["gfontsWeblist"]) ? json_decode($_POST["gfontsWeblist"]) : false ) ); + //$errorinfo[] = "gfontsWeblist = ".print_r($gfontsWeblist,true); + //$errorinfo[] = "gfontsWeblist->items = ".print_r($gfontsWeblist->items,true); + $totalFonts = (count($gfontsWeblist->items) > 0) ? count($gfontsWeblist->items) : false; + $errorinfo[] = "totalFonts according to the server script = ".$totalFonts; + } + else{ + $errorinfo[] = "We do not seem to have received all the necessary data... Request received: ".print_r($_POST,true); + echo json_encode($errorinfo); + wp_die(); + + } + + $access_type = get_filesystem_method(); + $plugin_path = ""; + if($access_type === 'direct'){ + $creds = request_filesystem_credentials(site_url() . '/wp-admin/', '', false, false, array()); + /* initialize the API */ + if ( WP_Filesystem($creds) ) { + global $wp_filesystem; + $plugin_path = str_replace(ABSPATH, $wp_filesystem->abspath(), plugin_dir_path( __FILE__ )); + + foreach($gfontsWeblist->items as $idx => $googlefont){ + if($idx >= $startIdx && $idx < ($startIdx + $batchLimit)){ + $thisfamily = $googlefont->family; + $familyurlname = preg_replace('/\s+/', '+', $thisfamily); + $familyfilename = preg_replace('/\s+/', '', $thisfamily); + $errorinfo[] = "Now dealing with font-family " . $thisfamily; + $fnttype = 'ttf'; //'woff', 'woff2', 'ttf' + + if(!file_exists($gfontsDir."{$familyfilename}.{$fnttype}") ){ //$idx < $idxlimit && + $ch2 = curl_init("https://fonts.googleapis.com/css2?family={$familyurlname}&text={$familyfilename}"); + curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, TRUE); + curl_setopt($ch2, CURLOPT_SSL_VERIFYHOST, 2); + curl_setopt($ch2, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2 ); + curl_setopt($ch2, CURLOPT_RETURNTRANSFER, TRUE ); + curl_setopt($ch2, CURLOPT_INTERFACE, $_SERVER['SERVER_ADDR']); + if (ini_get ( 'safe_mode' ) || ini_get ( 'open_basedir' )) { + // safe mode is on, we can't use some settings + } else { + curl_setopt($ch2, CURLOPT_FOLLOWLOCATION, TRUE ); + curl_setopt($ch2, CURLOPT_AUTOREFERER, TRUE ); + } + $response2 = curl_exec ( $ch2 ); + $status2 = (int) curl_getinfo($ch2, CURLINFO_HTTP_CODE); + if ($response2 && ! curl_errno ( $ch2 ) && $status2 == 200) { + if (preg_match('/url\((.*?)\)/', $response2, $match) == 1) { + $thisfonturl = $match[1]; + $errorinfo[] = "font retrieval url for {$thisfamily} = {$thisfonturl}"; + + // $ch3_headers = []; + $ch3 = curl_init($thisfonturl); + curl_setopt($ch3, CURLOPT_SSL_VERIFYPEER, TRUE); + curl_setopt($ch3, CURLOPT_SSL_VERIFYHOST, 2); + curl_setopt($ch3, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2 ); + curl_setopt($ch3, CURLOPT_RETURNTRANSFER, TRUE ); + curl_setopt($ch3, CURLOPT_INTERFACE, $_SERVER['SERVER_ADDR']); + //declaring acceptance of woff2 will make it possible to download the compressed version of the font with only the requested characters + //however it seems that the actual returned font will still be in ttf format, even though it is reduced to the requested characters + curl_setopt($ch3, CURLOPT_HTTPHEADER, array("Accept: font/woff2","Content-type: font/ttf")); + // curl_setopt($ch3, CURLOPT_HEADERFUNCTION, function($curl, $header) use (&$ch3_headers){ + // $len = strlen($header); + // $header = explode(':', $header, 2); + // if (count($header) < 2) // ignore invalid headers + // return $len; + // $ch3_headers[strtolower(trim($header[0]))][] = trim($header[1]); + // return $len; + // } + // ); + if (ini_get ( 'safe_mode' ) || ini_get ( 'open_basedir' )) { + // safe mode is on, we can't use some settings + } else { + curl_setopt($ch3, CURLOPT_FOLLOWLOCATION, TRUE ); + curl_setopt($ch3, CURLOPT_AUTOREFERER, TRUE ); + } + $response3 = curl_exec ( $ch3 ); + // $errorinfo[] = print_r($ch3_headers,TRUE); + $status3 = (int) curl_getinfo($ch3, CURLINFO_HTTP_CODE); + if ($response3 && ! curl_errno ( $ch3 ) && $status3 == 200) { + if($wp_filesystem){ + // if(!file_exists($plugin_path . "gfonts_preview/{$familyfilename}.{$fnttype}") ){ + if(!$wp_filesystem->put_contents( + $gfontsDir."{$familyfilename}.{$fnttype}", + $response3, + FS_CHMOD_FILE + )){ + $errorinfo[] = "Cannot write file ".$plugin_path . "gfonts_preview/{$familyfilename}.{$fnttype} with wordpress filesystem api, sorry"; + } + else{ + $gfont_stylesheet = preg_replace('/url\((.*?)\)/','url('.esc_url(plugins_url( "gfonts_preview/{$familyfilename}.{$fnttype}", __FILE__ )).')', $response2); + if(!file_exists($plugin_path . "css/gfonts_preview/{$familyfilename}.css") ){ + if(!$wp_filesystem->put_contents( + $plugin_path . "css/gfonts_preview/{$familyfilename}.css", + $gfont_stylesheet, + FS_CHMOD_FILE + )){ + $errorinfo[] = "Cannot write file ".$plugin_path . "css/gfonts_preview/{$familyfilename}.css with wordpress filesystem api, sorry"; + } + } + + } + // } + // else{ + // $errorinfo[] = "File " . $plugin_path . "gfonts_preview/{$familyfilename}.{$fnttype} already exists, skipping..."; + // } + } + } + else{ + if(!$response3){ + $errorinfo[] = "Response from curl request 3 is false for font-family {$thisfamily}"; + } + if(curl_errno($ch3)){ + $errorinfo[] = "Error on curl request 3 for font-family {$thisfamily}: " . curl_error($ch); + } + if($status3 != 200){ + $errorinfo[] = "Status on curl request 3 for font-family {$thisfamily}: " . $status; + } + } + + } + } + else{ + if(!$response2){ + $errorinfo[] = "Response from curl request 2 is false for font-family {$thisfamily}"; + } + if(curl_errno($ch2)){ + $errorinfo[] = "Error on curl request 2 for font-family {$thisfamily}: " . curl_error($ch); + } + if($status2 != 200){ + $errorinfo[] = "Status on curl request 2 for font-family {$thisfamily}: " . $status; + } + } + } + else{ + // if($idx >= $idxlimit){ + // $errorinfo[] = "You have reached the established index limit"; + // break; + // } + // else { + $errorinfo[] = "File ".$familyfilename.".{$fnttype} already exists"; + // } + } + } + + } + + + } + else{ + $errorinfo[] = "Could not initialize wordpress filesystem with these credentials"; + } + } + else{ + $errorinfo[] = "You do not have direct access permissions to the wordpress filesystem"; + } + + +// echo print_r($errorinfo); + if(($startIdx + ($batchLimit-1)) < ($totalFonts-1) ){ + $returnInfo->state = "RUN_PROCESSED"; + $returnInfo->run = $currentRun; + } + else{ + $returnInfo->state = "COMPLETE"; + + //LAST STEP IS TO MINIFY ALL OF THE CSS FILES INTO ONE SINGLE FILE + $cssdirectory = WP_PLUGIN_DIR."/bibleget-io/css/gfonts_preview"; + if(!file_exists($cssdirectory."/gfonts_preview.css")){ + $cssfiles = array_diff(scandir($cssdirectory), array('..', '.')); + + $minifier = new MatthiasMullie\Minify\CSS($cssdirectory."/".(array_shift($cssfiles))); + while(count($cssfiles) > 0){ + $minifier->add($cssdirectory."/".(array_shift($cssfiles))); + } + $minifier->minify($cssdirectory."/gfonts_preview.css"); + } + } + + if(count( $errorinfo) > 0){ + $returnInfo->errorinfo = array(); + $returnInfo->errorinfo = $errorinfo; + } + else{ + $returnInfo->errorinfo = false; + } + + echo json_encode($returnInfo); + wp_die(); } - - public function do_on_my_plugin_settings_save() + + + public function bibleget_plugin_settings_save() { //print("\n Page with hook ".$this->options_page_hook." was loaded and load hook was called."); //exit; @@ -350,7 +780,7 @@ public function do_on_my_plugin_settings_save() if($this->options === false ){ // let's set some default options } - + } } @@ -367,9 +797,9 @@ class BibleGet_Customize { public static $bibleget_style_settings; private static $websafe_fonts; - + public static function init(){ - + /* Define object that will contain all the information for all settings and controls */ self::$bibleget_style_settings = new stdClass(); @@ -377,17 +807,17 @@ public static function init(){ self::$bibleget_style_settings->bibleget_fontfamily = new stdClass(); self::$bibleget_style_settings->bibleget_fontfamily->dfault = 'Palatino Linotype'; self::$bibleget_style_settings->bibleget_fontfamily->title = __('Font Family for Biblical Quotes',"bibleget-io"); - self::$bibleget_style_settings->bibleget_fontfamily->type = 'fontselect'; + self::$bibleget_style_settings->bibleget_fontfamily->type = 'fontselect'; self::$bibleget_style_settings->bibleget_fontfamily->section = 'bibleget_paragraph_style_options'; /* Define bibleget_borderwidth setting and control */ self::$bibleget_style_settings->bibleget_borderwidth = new stdClass(); - self::$bibleget_style_settings->bibleget_borderwidth->dfault = '2'; + self::$bibleget_style_settings->bibleget_borderwidth->dfault = '2'; /* translators: "px" refers to pixels as used in CSS rules, do not translate */ self::$bibleget_style_settings->bibleget_borderwidth->title = __('Border-width for Biblical Quotes (in px)',"bibleget-io"); self::$bibleget_style_settings->bibleget_borderwidth->type = 'number'; self::$bibleget_style_settings->bibleget_borderwidth->section = 'bibleget_paragraph_style_options'; - + /* Define bibleget_borderstyle setting and control */ self::$bibleget_style_settings->bibleget_borderstyle = new stdClass(); self::$bibleget_style_settings->bibleget_borderstyle->dfault = 'solid'; @@ -408,23 +838,23 @@ public static function init(){ "inherit" => "inherit" ); self::$bibleget_style_settings->bibleget_borderstyle->section = 'bibleget_paragraph_style_options'; - - + + /* Define bibleget_bordercolor setting and control */ self::$bibleget_style_settings->bibleget_bordercolor = new stdClass(); self::$bibleget_style_settings->bibleget_bordercolor->dfault = '#d3d3d3'; self::$bibleget_style_settings->bibleget_bordercolor->title = __('Border-color for Biblical Quotes',"bibleget-io"); self::$bibleget_style_settings->bibleget_bordercolor->type = 'color'; self::$bibleget_style_settings->bibleget_bordercolor->section = 'bibleget_paragraph_style_options'; - - + + /* Define bibleget_bgcolor setting and control */ self::$bibleget_style_settings->bibleget_bgcolor = new stdClass(); self::$bibleget_style_settings->bibleget_bgcolor->dfault = '#ffffff'; self::$bibleget_style_settings->bibleget_bgcolor->title = __('Background color for Biblical Quotes',"bibleget-io"); self::$bibleget_style_settings->bibleget_bgcolor->type = 'color'; self::$bibleget_style_settings->bibleget_bgcolor->section = 'bibleget_paragraph_style_options'; - + /* Define bibleget_borderradius setting and control */ self::$bibleget_style_settings->bibleget_borderradius = new stdClass(); @@ -433,8 +863,8 @@ public static function init(){ self::$bibleget_style_settings->bibleget_borderradius->title = __('Border-radius for Biblical Quotes (in px)',"bibleget-io"); self::$bibleget_style_settings->bibleget_borderradius->type = 'number'; self::$bibleget_style_settings->bibleget_borderradius->section = 'bibleget_paragraph_style_options'; - - + + $margin_padding_vals = array( "auto" => "auto", 0 => "0", @@ -452,10 +882,10 @@ public static function init(){ 14 => "14", 16 => "16", 18 => "18", - 20 => "20" + 20 => "20" ); - + /* Define bibleget_margintopbottom setting and control */ self::$bibleget_style_settings->bibleget_margintopbottom = new stdClass(); self::$bibleget_style_settings->bibleget_margintopbottom->dfault = 12; @@ -464,8 +894,8 @@ public static function init(){ self::$bibleget_style_settings->bibleget_margintopbottom->type = 'select'; self::$bibleget_style_settings->bibleget_margintopbottom->choices = $margin_padding_vals; self::$bibleget_style_settings->bibleget_margintopbottom->section = 'bibleget_paragraph_style_options'; - - + + /* Define bibleget_marginleftright setting and control */ self::$bibleget_style_settings->bibleget_marginleftright = new stdClass(); self::$bibleget_style_settings->bibleget_marginleftright->dfault = 'auto'; @@ -475,7 +905,7 @@ public static function init(){ self::$bibleget_style_settings->bibleget_marginleftright->choices = $margin_padding_vals; self::$bibleget_style_settings->bibleget_marginleftright->section = 'bibleget_paragraph_style_options'; - + /* Define bibleget_paddingtopbottom setting and control */ self::$bibleget_style_settings->bibleget_paddingtopbottom = new stdClass(); self::$bibleget_style_settings->bibleget_paddingtopbottom->dfault = 12; @@ -485,7 +915,7 @@ public static function init(){ self::$bibleget_style_settings->bibleget_paddingtopbottom->choices = $margin_padding_vals; self::$bibleget_style_settings->bibleget_paddingtopbottom->section = 'bibleget_paragraph_style_options'; - + /* Define bibleget_paddingleftright setting and control */ self::$bibleget_style_settings->bibleget_paddingleftright = new stdClass(); self::$bibleget_style_settings->bibleget_paddingleftright->dfault = 12; @@ -494,7 +924,7 @@ public static function init(){ self::$bibleget_style_settings->bibleget_paddingleftright->type = 'select'; self::$bibleget_style_settings->bibleget_paddingleftright->choices = $margin_padding_vals; self::$bibleget_style_settings->bibleget_paddingleftright->section = 'bibleget_paragraph_style_options'; - + /* Define bibleget_width setting and control */ self::$bibleget_style_settings->bibleget_width = new stdClass(); @@ -502,9 +932,9 @@ public static function init(){ /* translators: "%" refers to percentage as used in CSS rules (width: 100%), do not translate */ self::$bibleget_style_settings->bibleget_width->title = __('Width for Biblical Quotes (in %)',"bibleget-io"); self::$bibleget_style_settings->bibleget_width->type = 'number'; - self::$bibleget_style_settings->bibleget_width->section = 'bibleget_paragraph_style_options'; - - + self::$bibleget_style_settings->bibleget_width->section = 'bibleget_paragraph_style_options'; + + /* Define bibleget_textalign setting and control */ self::$bibleget_style_settings->bibleget_textalign = new stdClass(); self::$bibleget_style_settings->bibleget_textalign->dfault = 'justify'; @@ -512,23 +942,23 @@ public static function init(){ self::$bibleget_style_settings->bibleget_textalign->type = 'select'; self::$bibleget_style_settings->bibleget_textalign->choices = array('left' => 'left','right'=>'right','center'=>'center','justify'=>'justify','inherit'=>'inherit','start'=>'start','end'=>'end'); self::$bibleget_style_settings->bibleget_textalign->section = 'bibleget_paragraph_style_options'; - - - + + + $bibleget_styles_general = new stdClass(); $bibleget_styles_general->font_size = new stdClass(); $bibleget_styles_general->font_style = new stdClass(); $bibleget_styles_general->font_color = new stdClass(); - + /* translators: "pt" refers to points as used in CSS rules, do not translate */ $bibleget_styles_general->font_size->title = __("Font Size (in pt)","bibleget-io"); $bibleget_styles_general->font_style->title = __("Font Style","bibleget-io"); $bibleget_styles_general->font_color->title = __("Font Color","bibleget-io"); - + $bibleget_styles_general->font_size->type = 'select'; $bibleget_styles_general->font_style->type = 'style'; $bibleget_styles_general->font_color->type = 'color'; - + $bibleget_style_sizes_arr = array(4=>'4',5=>'5',6=>'6',7=>'7',8=>'8',9=>'9',10=>'10',11=>'11',12=>'12',14=>'14',16=>'16',18=>'18',20=>'20',22=>'22',24=>'24',26=>'26',28=>'28'); $bibleget_style_choices_arr = array( 'bold' => __("B","bibleget-io"), @@ -538,7 +968,7 @@ public static function init(){ 'superscript' => __("SUP","bibleget-io"), 'subscript' => __("SUB","bibleget-io") ); - + foreach($bibleget_styles_general as $i => $styleobj){ $o = str_replace("_","",$i); @@ -553,7 +983,7 @@ public static function init(){ elseif($styleobj->type == 'style'){ self::$bibleget_style_settings->{'version_'.$o}->choices = $bibleget_style_choices_arr; } - + self::$bibleget_style_settings->{'bookchapter_'.$o} = new stdClass(); self::$bibleget_style_settings->{'bookchapter_'.$o}->section = 'bibleget_bookchapter_style_options'; /* translators: in reference to Font Size, Style and Color */ @@ -565,7 +995,7 @@ public static function init(){ elseif($styleobj->type == 'style'){ self::$bibleget_style_settings->{'bookchapter_'.$o}->choices = $bibleget_style_choices_arr; } - + self::$bibleget_style_settings->{'versenumber_'.$o} = new stdClass(); self::$bibleget_style_settings->{'versenumber_'.$o}->section = 'bibleget_versenumber_style_options'; /* translators: in reference to Font Size, Style and Color */ @@ -577,7 +1007,7 @@ public static function init(){ elseif($styleobj->type == 'style'){ self::$bibleget_style_settings->{'versenumber_'.$o}->choices = $bibleget_style_choices_arr; } - + self::$bibleget_style_settings->{'versetext_'.$o} = new stdClass(); self::$bibleget_style_settings->{'versetext_'.$o}->section = 'bibleget_versetext_style_options'; /* translators: in reference to Font Size, Style and Color */ @@ -598,22 +1028,22 @@ public static function init(){ self::$bibleget_style_settings->bookchapter_fontsize->dfault = 14; self::$bibleget_style_settings->bookchapter_fontstyle->dfault = 'bold'; self::$bibleget_style_settings->bookchapter_fontcolor->dfault = '#284f29'; - + self::$bibleget_style_settings->versenumber_fontsize->dfault = 7; self::$bibleget_style_settings->versenumber_fontstyle->dfault = 'superscript'; self::$bibleget_style_settings->versenumber_fontcolor->dfault = '#c10005'; - + self::$bibleget_style_settings->versetext_fontsize->dfault = 10; self::$bibleget_style_settings->versetext_fontstyle->dfault = ''; self::$bibleget_style_settings->versetext_fontcolor->dfault = '#646d73'; - + self::$bibleget_style_settings->linespacing_verses = new stdClass(); self::$bibleget_style_settings->linespacing_verses->dfault = 150; self::$bibleget_style_settings->linespacing_verses->title = __('Line-spacing for Verses Paragraphs',"bibleget-io"); self::$bibleget_style_settings->linespacing_verses->type = 'select'; self::$bibleget_style_settings->linespacing_verses->choices = array(100 => 'single',150 => '1½',200 => 'double'); self::$bibleget_style_settings->linespacing_verses->section = 'bibleget_paragraph_style_options'; - + self::$websafe_fonts = array( array("font-family" => "Arial", "fallback" => "Helvetica", "generic-family" => "sans-serif"), array("font-family" => "Arial Black", "fallback" => "Gadget", "generic-family" => "sans-serif"), @@ -651,12 +1081,12 @@ public static function get_font_index($fontfamily){ * @since BibleGet I/O 3.6 */ public static function register ( $wp_customize ) { - + self::init(); - + require_once 'custom_controls.php'; - - $wp_customize->add_panel('bibleget_style_options', + + $wp_customize->add_panel('bibleget_style_options', array( 'priority' => 35, 'capability' => 'edit_theme_options', @@ -665,7 +1095,7 @@ public static function register ( $wp_customize ) { 'description' => __( 'Custom styles that apply to the text formatting of the biblical quotes', 'bibleget-io' ) ) ); - + $wp_customize->add_section( 'bibleget_paragraph_style_options', array( 'priority' => 10, //Determines what order this appears in @@ -676,7 +1106,7 @@ public static function register ( $wp_customize ) { 'panel' => 'bibleget_style_options' ) ); - + $wp_customize->add_section( 'bibleget_bibleversion_style_options', array( 'priority' => 20, //Determines what order this appears in @@ -687,7 +1117,7 @@ public static function register ( $wp_customize ) { 'panel' => 'bibleget_style_options' ) ); - + $wp_customize->add_section( 'bibleget_bookchapter_style_options', array( 'priority' => 30, //Determines what order this appears in @@ -709,7 +1139,7 @@ public static function register ( $wp_customize ) { 'panel' => 'bibleget_style_options' ) ); - + $wp_customize->add_section( 'bibleget_versetext_style_options', array( 'priority' => 50, //Determines what order this appears in @@ -720,10 +1150,10 @@ public static function register ( $wp_customize ) { 'panel' => 'bibleget_style_options' ) ); - + $bibleget_style_settings_cc = 0; foreach(self::$bibleget_style_settings as $style_setting => $style_setting_obj){ - + //2. Register new settings to the WP database... $wp_customize->add_setting( $style_setting, //No need to use a SERIALIZED name, as `theme_mod` settings already live under one db record array( @@ -732,8 +1162,8 @@ public static function register ( $wp_customize ) { 'capability' => 'edit_theme_options', //Optional. Special permissions for accessing this setting. 'transport' => 'postMessage' //What triggers a refresh of the setting? 'refresh' or 'postMessage' (instant)? ) - ); - + ); + //3. Finally, we define the control itself (which links a setting to a section and renders the HTML controls)... if($style_setting_obj->type == 'color'){ $wp_customize->add_control( new WP_Customize_Color_Control( //Instantiate the color control class @@ -746,7 +1176,7 @@ public static function register ( $wp_customize ) { 'section' => $style_setting_obj->section //ID of the section this control should render in (can be one of yours, or a WordPress default section) ) ) - ); + ); } elseif($style_setting_obj->type == 'select'){ $wp_customize->add_control($style_setting . '_ctl', @@ -795,14 +1225,14 @@ public static function register ( $wp_customize ) { 'settings' => $style_setting, 'priority' => $bibleget_style_settings_cc++, 'section' => $style_setting_obj->section, - 'type' => 'number' + 'type' => 'number' ) ); } } - - + + } @@ -817,10 +1247,11 @@ public static function register ( $wp_customize ) { public static function header_output() { self::init(); ?> - + bibleget_fontfamily->dfault); - if( ! empty( $mod ) ) { + //echo ''; + if( ! empty( $mod ) ) { //let's check if it's a websafe font or a google font if(self::get_font_index($mod) === false){ //not a websafe font, so most probably a google font... @@ -828,11 +1259,11 @@ public static function header_output() { $is_googlefont = true; echo ''; } - + } ?> + 'postMessage' instead of the default 'transport' * => 'refresh' - * + * * Used by hook: 'customize_preview_init' - * + * * @see add_action('customize_preview_init',$func) * @since BibleGet I/O 3.6 */ public static function live_preview() { - wp_enqueue_script( + wp_enqueue_script( 'bibleget-pluginstylecustomizer', // Give the script a unique ID plugins_url( 'js/theme-customizer.js', __FILE__ ), // Define the path to the JS file array( 'jquery', 'customize-preview' ), // Define dependencies - '', // Define a version (optional) + '', // Define a version (optional) true // Specify whether to put in footer (leave this true) ); } @@ -1048,7 +1479,7 @@ public static function live_preview() { /** * This will generate a line of CSS for use in header output. If the setting * ($mod_name) has no defined value, the CSS will not be output. - * + * * @uses get_theme_mod() * @param string $selector CSS selector * @param string $style The name of the CSS *property* to modify diff --git a/readme.txt b/readme.txt index 27b786a..014f4dc 100644 --- a/readme.txt +++ b/readme.txt @@ -3,8 +3,8 @@ Contributors: Lwangaman Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HDS7XQKGFHJ58 Tags: bible,shortcode,quote,citation,verses Requires at least: 3.3 -Tested up to: 4.9 -Stable tag: 4.9 +Tested up to: 5.3.2 +Stable tag: 5.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -71,6 +71,33 @@ At least the first query (of a series of queries chained by a semi-colon) must i When a query following a semi-colon does not indicate the book name, it is intended that the request be made upon the same book as the previous query. So “Gen1:7-9;4:4-5;Ex3:19” means “Genesis chapter 1, verses 7 to 9; then again Genesis chapter 4, verses 4 to 5; then Exodus chapter 3, verse 19”. += What happens if I add a Google Fonts API key? = +[ENGLISH] +If you add a Google Fonts API key, the BibleGet plugin will immediately test it's validity. +If valid, it will remember that you have a key and that it's valid for 3 months. +Every three months starting from this moment the BibleGet plugin will talk with the Google Fonts API +to get the latest list of available Google Fonts, and will download to the plugin folders a local compressed +copy of each of those fonts for the purpose of previewing them in the customizer interface. +You will need to be a bit patient the first time as it will take a couple minutes to complete the download process. +A progress bar will let you know how the download is progressing. If you have a slow connection, +the progress might stall for a few seconds every now an then (around 25%, 50%, and 75%), +just be patient and it should continue to progress to the end. In the future, whenever the plugin +talks with the Google Fonts API, the process should go a lot faster as it will only need to download new fonts. +It will also generate a css file that will load the preview of the fonts when you open the customizer interface. +This does have a bit of a performance impact, and especially the first time you open the customizer it might take a minute to load. +After this it should go a little faster as the fonts previews should be cached by the browser. +If you are not happy with the performance impact, I would suggest to delete the Google Fonts API key. + += I have added the Google Fonts API key but the list of available fonts isn't updated = +[ENGLISH] +The BibleGet plugin will remember that your key is valid for 3 months. +This means that it will not fetch the list of fonts from the Google Fonts API until the relative transient expires. +If a new font has come out that you would like to see and use in the customizer interface for the BibleGet plugin, +and you don't want to have to wait until the transient expires in that 3 month time slot, then you could use a transient manager +to look for a transient which has a value of "SUCCESS" and a long key of seemingly random characters; +this is most probably the one you need to delete. Once the transient is deleted, go back to the admin interface for the BibleGet plugin +and it will automatically start talking with the Google Fonts API again. The newer fonts previews should be downloaded locally +and become available in the customizer interface for the BibleGet plugin. == Screenshots == @@ -81,6 +108,10 @@ At least the first query (of a series of queries chained by a semi-colon) must i == Changelog == += 5.0 = +* verified compatibility with Wordpress 5.3.2 +* added option for Google Fonts API key + = 4.9 = * Bugfix: corrected evaluation of shortcode parameters for correct implementation of versions and popup functionality * verified compatibility with Wordpress 4.9 @@ -223,8 +254,11 @@ At least the first query (of a series of queries chained by a semi-colon) must i == Upgrade Notice == += 5.0 = +Versions prior to 3.6 must be updated. v5.0 verifies compatibility with Wordpress 5.3.2 and adds Google Fonts API option + = 4.9 = -Versions prior to 3.6 must be updated. v4.9 corrects evaluation of shortcode paramters for correct implementation of "popup" parameter functionality +Versions prior to 3.6 must be updated. v4.9 corrects evaluation of shortcode parameters for correct implementation of "popup" parameter functionality = 4.8 = Versions prior to 3.6 must be updated. v4.8 adds a parameter "popup" to the [bibleget] shortcode, to allow hiding the contents of the bible quote and show it only on click in a popup