Activating Basic HTML Mode For Gmail

Sometimes the full Gmail experience is too much for an older laptop or mobile device. Instead of trying to load the new Gmail, you can force the basic HTML version of Gmail to load by going to mail.google.com/?ui=html .

If you’re already signed in, you might see the below screen. If you’re signed out, you’ll need to sign in using the standard login screen.

Google confirming you want to use HTML mail.

After this, you’ll see a much stripped down version of Gmail:

I have way too much email in my inbox!

Creating A WordPress Blog Slug Part 2 – Python

In a previous post, I posted a sample NodeJS function to assemble a WordPress blog slug. I ended up rewriting part of the larger application (and the function itself) in Python.

In the below function, source is a blog title string, and it returns a slug suitable for use in a blog URL.

def generate_slug(source):
    i = 0
    source = source.lower().strip()
    allowed = "abcdefghijklmnopqrstuvwxyz1234567890"
    slug = ""
    while i < (len(source) - 0):
        single_letter = source[i:i+1]
        if single_letter in allowed:
            slug += single_letter
        elif not slug.endswith("-"):
            #letter is not allowed
            #check that the slug doesn't already end in a dash
            slug += "-"
        i = i + 1
    return slug

Utility Functions To Save To Google Cloud Storage

Here are short utility functions used to save to Google Cloud Storage in a Java App Engine application.

These snippets require the Java Cloud Storage library ( com.google.appengine.tools.cloudstorage.GcsService ). The bucket string is the name of the bucket, no gs:// required. folder_path is the subdirectory you want to save the file under. It should end with a forward slash. For example this/is/a/subdirectory/ . If you do not want a subdirectory, pass an empty string (“”). filename is the filename of the file you want to save, while contents is the data being saved.

There are two functions here. The top is intended to quickly save simple text/html/xml/etc files, while the bottom is intended to save binary files such as images, executables, and so forth. The bottom function includes a filetype argument, which should be filled with the appropriate MIME type. For example: image/png, image/jpg, application/octet-stream.

Reminder: GCS innately views files as individual objects. When you specify a subfolder, the filename for the object itself includes the folder path. When you read the file back from Google cloud storage, you need to include the folder path: for example this/is/a/subdirectory/example.png .

	public static void saveStringToGCS(String bucket, String folder_path, String filename, String contents) throws IOException {
		GcsService storage_service = GcsServiceFactory.createGcsService(RetryParams.getDefaultInstance());
		GcsFilename to_file = new GcsFilename(bucket, folder_path + filename);
		GcsFileOptions file_options = GcsFileOptions.getDefaultInstance();
		storage_service.createOrReplace(to_file, file_options, ByteBuffer.wrap(contents.getBytes(StandardCharsets.UTF_8)));
	}
	
	public static void saveByteBufferToGCS(String bucket, String folder_path, String filename, ByteBuffer contents, String filetype) throws IOException {
		GcsService storage_service = GcsServiceFactory.createGcsService(RetryParams.getDefaultInstance());
		GcsFilename to_file = new GcsFilename(bucket, folder_path + filename);
		GcsFileOptions file_options = (new GcsFileOptions.Builder()).mimeType(filetype).build();
		storage_service.createOrReplace(to_file, file_options, contents);
	}

Google Doodle: Seiichi Miyake

Today’s Google doodle celebrates Seiichi Miyake, who invented paving slabs with tactile feedback, allowing the blind and visually impaired to navigate the world.

Here’s the Google home page with the doodle:

Here’s the doodle itself:

The Google doodle for March 18, 2019.

The Google doodle links to a search for Seiichi Miyake:

Google Doodle: St. Patrick’s Day

Google celebrates St. Patrick’s Day today, March 17. Here’s a screenshot of Google’s home page with the doodle:

Google’s home page with the St. Patrick’s Day doodle.

The doodle itself is animated: the oo in Google shifts around:

Clicking on the doodle links to a search for St. Patrick’s Day:

A HTTP GET Example Using The Apache HTTPClient Library

Here’s a quick example of using the Apache HTTPClient library to issue a simple GET request. The URL you’re connecting to is in endpoint, and the contents of the URL can be read from the BufferedReader response_reader.

		HttpGet get_request = new HttpGet(endpoint);
		get_request.addHeader(HttpHeaders.USER_AGENT, "Example Reader Service");

		HttpResponse http_response = HttpClientBuilder.create().build().execute(get_request);
		content_type_header = http_response.getFirstHeader("Content-Type").getValue();
		
		int response_code = http_response.getStatusLine().getStatusCode();

		if (response_code != 200) {
			throw new IOException("Response code is not 200 OK. Response code: " + response_code + " : " + endpoint.toString());
		}

		//Pull out text response
		InputStream response_is = http_response.getEntity().getContent();
		BufferedReader response_reader = new BufferedReader(new InputStreamReader(response_is, "UTF-8"));

Mapping Unicode Punctuation To ASCII Punctuation

The following code maps a bunch of unicode punctuation to their more normal ASCII counterparts. For example, the Unicode character LEFT DOUBLE QUOTATION MARK is mapped to the ASCII double quotation mark: “.

		Hashtable<String, String> map = new Hashtable<String, String>();
		map.put(new String(Character.toChars(0x00AB)), new String("\""));
		map.put(new String(Character.toChars(0x00AD)), "-");
		map.put(new String(Character.toChars(0x00B4)), "\'");
		map.put(new String(Character.toChars(0x00BB)), "\"");
		map.put(new String(Character.toChars(0x00F7)), "/");
		map.put(new String(Character.toChars(0x01C0)), "|");
		map.put(new String(Character.toChars(0x01C3)), "!");
		map.put(new String(Character.toChars(0x02B9)), "\'");
		map.put(new String(Character.toChars(0x02BA)), "\"");
		map.put(new String(Character.toChars(0x02BC)), "\'");
		map.put(new String(Character.toChars(0x02C4)), "^");
		map.put(new String(Character.toChars(0x02C6)), "^");
		map.put(new String(Character.toChars(0x02C8)), "\'");
		map.put(new String(Character.toChars(0x02CB)), "`");
		map.put(new String(Character.toChars(0x02CD)), "_");
		map.put(new String(Character.toChars(0x02DC)), "~");
		map.put(new String(Character.toChars(0x0300)), "`");
		map.put(new String(Character.toChars(0x0301)), "\'");
		map.put(new String(Character.toChars(0x0302)), "^");
		map.put(new String(Character.toChars(0x0303)), "~");
		map.put(new String(Character.toChars(0x030B)), "\"");
		map.put(new String(Character.toChars(0x030E)), "\"");
		map.put(new String(Character.toChars(0x0331)), "_");
		map.put(new String(Character.toChars(0x0332)), "_");
		map.put(new String(Character.toChars(0x0338)), "/");
		map.put(new String(Character.toChars(0x0589)), ":");
		map.put(new String(Character.toChars(0x05C0)), "|");
		map.put(new String(Character.toChars(0x05C3)), ":");
		map.put(new String(Character.toChars(0x066A)), "%");
		map.put(new String(Character.toChars(0x066D)), "*");
		map.put(new String(Character.toChars(0x200B)), " ");
		map.put(new String(Character.toChars(0x2010)), "-");
		map.put(new String(Character.toChars(0x2011)), "-");
		map.put(new String(Character.toChars(0x2012)), "-");
		map.put(new String(Character.toChars(0x2013)), "-");
		map.put(new String(Character.toChars(0x2014)), "-");
		map.put(new String(Character.toChars(0x2015)), "-");
		map.put(new String(Character.toChars(0x2016)), "|");
		map.put(new String(Character.toChars(0x2017)), "_");
		map.put(new String(Character.toChars(0x2018)), "\'");
		map.put(new String(Character.toChars(0x2019)), "\'");
		map.put(new String(Character.toChars(0x201A)), ",");
		map.put(new String(Character.toChars(0x201B)), "\'");
		map.put(new String(Character.toChars(0x201C)), "\"");
		map.put(new String(Character.toChars(0x201D)), "\"");
		map.put(new String(Character.toChars(0x201E)), "\"");
		map.put(new String(Character.toChars(0x201F)), "\"");
		map.put(new String(Character.toChars(0x2032)), "\'");
		map.put(new String(Character.toChars(0x2033)), "\"");
		map.put(new String(Character.toChars(0x2034)), "\'");
		map.put(new String(Character.toChars(0x2035)), "`");
		map.put(new String(Character.toChars(0x2036)), "\"");
		map.put(new String(Character.toChars(0x2037)), "\'");
		map.put(new String(Character.toChars(0x2038)), "^");
		map.put(new String(Character.toChars(0x2039)), "<");
		map.put(new String(Character.toChars(0x203A)), ">");
		map.put(new String(Character.toChars(0x203D)), "?");
		map.put(new String(Character.toChars(0x2044)), "/");
		map.put(new String(Character.toChars(0x204E)), "*");
		map.put(new String(Character.toChars(0x2052)), "%");
		map.put(new String(Character.toChars(0x2053)), "~");
		map.put(new String(Character.toChars(0x2060)), " ");
		map.put(new String(Character.toChars(0x20E5)), "\\");
		map.put(new String(Character.toChars(0x2212)), "-");
		map.put(new String(Character.toChars(0x2215)), "/");
		map.put(new String(Character.toChars(0x2216)), "\\");
		map.put(new String(Character.toChars(0x2217)), "*");
		map.put(new String(Character.toChars(0x2223)), "|");
		map.put(new String(Character.toChars(0x2236)), ":");
		map.put(new String(Character.toChars(0x223C)), "~");
		map.put(new String(Character.toChars(0x2264)), "<");
		map.put(new String(Character.toChars(0x2265)), ">");
		map.put(new String(Character.toChars(0x2266)), "<");
		map.put(new String(Character.toChars(0x2267)), ">");
		map.put(new String(Character.toChars(0x2303)), "^");
		map.put(new String(Character.toChars(0x2329)), "<");
		map.put(new String(Character.toChars(0x232A)), ">");
		map.put(new String(Character.toChars(0x266F)), "#");
		map.put(new String(Character.toChars(0x2731)), "*");
		map.put(new String(Character.toChars(0x2758)), "|");
		map.put(new String(Character.toChars(0x2762)), "!");
		map.put(new String(Character.toChars(0x27E6)), "[");
		map.put(new String(Character.toChars(0x27E8)), "<");
		map.put(new String(Character.toChars(0x27E9)), ">");
		map.put(new String(Character.toChars(0x2983)), "{");
		map.put(new String(Character.toChars(0x2984)), "}");
		map.put(new String(Character.toChars(0x3003)), "\"");
		map.put(new String(Character.toChars(0x3008)), "<");
		map.put(new String(Character.toChars(0x3009)), ">");
		map.put(new String(Character.toChars(0x301B)), "]");
		map.put(new String(Character.toChars(0x301C)), "~");
		map.put(new String(Character.toChars(0x301D)), "\"");
		map.put(new String(Character.toChars(0x301E)), "\"");
		map.put(new String(Character.toChars(0xFEFF)), " ");

Creating A WordPress Blog Slug – NodeJS

A slug in WordPress is the part of the URL that references the blog title. For example, if the URL looks like example.com/2019/this-is-my-test-post, then this-is-my-test-post would be a slug. Typically a slug is all letters and numbers, with any other character being replaced by a dash.

The below code fragment is a simple JS function to reduce a blog title down to a slug – you may want to add some additional code to guarantee a certain slug length.


var generateSlug = function generateSlug(title) {
  var allowable_characters = "abcdefghijklmnopqrstuvwxyz1234567890";
  
  //Builds our own slug
  title = title.trim().toLowerCase();
  var title_array = title.split("");
  
  var outbound_title = " ";
  for ( var i = 0; i < title_array.length; i++) {
    var title_char = title_array[i];
    if ( allowable_characters.indexOf(title_char) != -1 ) {
      outbound_title = outbound_title + title_char;
    }
    else if ( outbound_title.split("").pop() != "-" ) {
      outbound_title = outbound_title + "-";
    }
  }
  
  console.log("Generated slug: " + outbound_title);
  
  return outbound_title.trim();
  
}//end generateSlug

Querying For Previous Published WordPress Posts

The following code example pulls out the last 5 published WordPress posts by their ID, extracts the first ID (which is the last published post ID) and then extracts the post’s tags into an array.

$return_tag_array is a list of the last published post’s tags.

  //Get list of past published posts, up to 5
  $args = array(
	'numberposts' => 5,
	'offset' => 0,
	'category' => 0,
	'orderby' => 'post_date',
	'order' => 'DESC',
	'include' => '',
	'exclude' => '',
	'meta_key' => '',
	'meta_value' =>'',
	'post_type' => 'post',
	'post_status' => 'publish',
	'suppress_filters' => true
);
	
  $published_posts = wp_get_recent_posts( $args, ARRAY_A );

  //Pull off the top most post, & retrieve the ID
  $last_published_post = reset($published_posts);
  $last_published_post_id = $last_published_post["ID"];

  //TAGS	
  //Use the post ID to pull off tags
  $tags = wp_get_post_tags($last_published_post_id);
  $return_tag_array = array();	
  foreach ($tags as $tag) {
	  $tag_name = $tag->name;
	  array_push($return_tag_array, $tag_name);
  }

Google Doodle: 30th Anniversary Of The World Wide Web

Today’s Google doodle celebrates the 30th anniversary of the world wide web. Here’s a screenshot of today’s Google front page:

Google front page for March 12, 2019.

Here’s the doodle itself:

The Google doodle for March 12, 2019.

Clicking on the doodle performs a Google search for World Wide Web:

Clicking on the doodle Google search.

On the Google front page, clicking on the text Happy Birthday to the World Wide Web goes to a Google Arts & Culture page discussing the history of the Internet: