MacBook, defective by design banner

title:
Put the knife down and take a green herb, dude.


descrip:

One feller's views on the state of everyday computer science & its application (and now, OTHER STUFF) who isn't rich enough to shell out for www.myfreakinfirst-andlast-name.com

Using 89% of the same design the blog had in 2001.

FOR ENTERTAINMENT PURPOSES ONLY!!!
Back-up your data and, when you bike, always wear white.

As an Amazon Associate, I earn from qualifying purchases. Affiliate links in green.

x

MarkUpDown is the best Markdown editor for professionals on Windows 10.

It includes two-pane live preview, in-app uploads to imgur for image hosting, and MultiMarkdown table support.

Features you won't find anywhere else include...

You've wasted more than $15 of your time looking for a great Markdown editor.

Stop looking. MarkUpDown is the app you're looking for.

Learn more or head over to the 'Store now!

Friday, December 23, 2022

Ah, one quick Markdown lesson I learned recently.

If you've got Markdown inside of "real" block-level html tags, it's not supposed to be rendered.

<div>This is **some Markdown**.</div>

That shouldn't be bold. It renders as...

This is **some Markdown**.

Unexpected, but (with a hat tip to this SO answer), apparently correct behavior according to The Grubes:

The only restrictions are that block-level HTML elementsโ€‰โ€”โ€‰e.g.ย <div>,ย <table>,ย <pre>,ย <p>, etc.โ€‰โ€”โ€‰must be separated from surrounding content by blank lines, and the start and end tags of the block should not be indented with tabs or spaces. Markdown is smart enough not to add extra (unwanted)ย <p>ย tags around HTML block-level tags.

...

Note that Markdown formatting syntax is not processed within block-level HTML tags. E.g., you canโ€™t use Markdown-styleย emphasisย inside an HTML block.

Welcome to the land of unintended consequences. It looks like the deal was "stop adding all these danged <p> tags around my inline block-level html; it'd duping the breaks," and we got, "stop ALL markdown rendering in block tags" instead.

There is, however, a non-standard workaround, as described by Python-Markdown's docs:

Theย markdownย attribute can be assigned one of three values:ย "1",ย "block", orย "span".

Note: The expressions โ€œblock-levelโ€ and โ€œspan-levelโ€ as used in this document refer to an elementโ€™s designation according to the HTML specification. Whereas theย "span"ย andย "block"ย values assigned to theย markdownย attribute refer to the Markdown parserโ€™s behavior.

markdown="1"

When theย markdownย attribute is set toย "1", then the parser will use the default behavior for that specific tag.

So if you have

<div markdown="1">This is **some Markdown**.</div>

you should have

This is some Markdown.

... but I need to add that to MarkUpDown if I want to support it. And since it's not like someone is going to add that that doesn't want it, I guess I should!

Labels: , , ,


posted by ruffin at 12/23/2022 08:36:00 AM
Friday, January 24, 2020

Added Disqus comments to the blog today. I imagine they do all sorts of nasty things behind the scenes with cookies and JavaScript. I apologize for that in advance -- though see below. The way I've done it, you'll only get that nastiness if you go to a single-post page by permalink.

Note also that I use the really old version of Blogger where I have my own html theme with some Blogger variables (like <$BlogItemPermalinkURL$>) sprinkled within. Let's just say that the instructions to add Disqus to Blogger are out of date for dinosaurs like me.

Here's what I added to my template. Neat plus: It's not loaded at all on my front page, and since every post is listed in its entirety there, you shouldn't get any Disqus nastiness unless you go to a specific post. That said, I've always kinda liked Disqus as a comment manager, so I hope you'll find it useful.

<!-- Disqus comments -->
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
    this.page.url = "<$BlogItemPermalinkURL$>";  // Replace PAGE_URL with your page's canonical URL variable
    this.page.identifier = "<$BlogItemNumber$>"; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};

(function () { // DON'T EDIT BELOW THIS LINE <<< MUAHAHAHAHA!!! I did anyway. Because I needed to.
    if (
        "/" !== window.location.pathname                                // on the home page
        && "" !== window.location.pathname                              // on the home page with IE < 11, _mayhbe_
        && !window.location.pathname.match(/^\/*[0-9]+\/[0-9]+\/*$/)    // archive pages
        && window.location.pathname.indexOf("search") == -1             // tag search pages
    ) {
        var d = document, s = d.createElement('script');
        s.src = 'https://myfreakinname.disqus.com/embed.js';
        s.setAttribute('data-timestamp', +new Date());
        (d.head || d.body).appendChild(s);
    }
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<!-- eo Disqus comments -->

Key lines:

this.page.url = "<$BlogItemPermalinkURL$>";  // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = "<$BlogItemNumber$>"; // Replace PAGE_IDENTIFIER with your page's unique identifier variable

I'm pretty sure those are the Blogger variables you want to use for those two properties.

And then le piece de resistance. Or whatever.

    if (
        "/" !== window.location.pathname                                // on the home page
        && "" !== window.location.pathname                              // on the home page with IE < 11, _mayhbe_
        && !window.location.pathname.match(/^\/*[0-9]+\/[0-9]+\/*$/)    // archive pages
        && window.location.pathname.indexOf("search") == -1             // tag search pages
    ) {   

By adding that check in the shudder area Disqus says not to edit, you make it so that Disqus isn't loaded on your home page (or on archive review pages like this one), which is good, because who wants Disqus on every freaking post on your home page? That'd be lots of wasted space.

Taking the Disqus UI off of posts on the home page of the blog is also good because the UI will only pop up under the first post on the page. That's because Disqus doesn't honor multiple instances of its UI on the same URL. Which leads us into Good Thing #3: Those comments on the first page would forever be for the first post on the home page, which would change from day to day. So it's an important check.

Anyhow, with that info in hand, all you dinosaur Bloggers can add Disqus invasive nastiness to your posts too and enable comments in a manner that's much more mature than all the crap Google and Google+ has tried to pull (and then pull back!) over the years.

Labels: , ,


posted by ruffin at 1/24/2020 11:53:00 AM
Tuesday, May 08, 2018

Recently, I've been playing around with this pretty good howto for Reduxless React SSR, which needed a few tweaks to work.

Once things were running, and I could tell in Chrome's network tab that I was receiving good, pre-rendered [by the server] content, I had some difficulty as an SSR n00b figuring out if the client was wasting time re-rendering or not. I take that back -- render was being called on the client in all of my test app's components, though with SSR they seemingly shouldn't, and I wanted to see if...

  1. The DOM was also changing, and
  2. If I c/sh/ould stop that initial render, even if it was "free".*

* In the second point, what I mean by "free" is that if render is called but nothing's changed -- the SSR completely created your initial state -- there's no practical impact on or for the user if the client wastes a few cycles after initial page render. Those wasted cycles are free, so to speak, as there was nothing else to spend them on. Not great, but no practical problem.

I messed around with the React extension in Chrome for a while, and it looked like things were moving quickly/not manipulating DOM after load. Adding SSR to the test app I'd initially written with client-side-only rendering felt like a win. But this exercise also told me I wasn't familiar enough with React's decision-making process for when it'd decide to call render. Why was render wasting cycles? I'd SSR'd, dang it!

Luckily, I bumped into How does React decide to re-render a component? at lucybain.com that discusses exactly that:

A re-render can only be triggered if a componentโ€™s state has changed. The state can change from aย propsย change, or from a directย setStateย change. The component gets the updated state and React decides if it should re-render the component. Unfortunately, by default React is incredibly simplistic and basically re-renders everything all the time.

Component changed? Re-render. Parent changed? Re-render. Section of props that doesn't actually impact the view changed? Re-render. [emph mine -mfn]

Hearing React wasn't exceptionally choosy about when to refire render made me feel better about all the render calls I saw, even after SSR. My components seem to be rendering on the client side, but it was only in the virtual DOM. That would seem to have to happen to compare the client-rolled DOM to the existing SSR'd DOM.

That means when it comes to the client-side render calls after successful SSR, I believe the answers to my above questions are...

  1. No, the client is not changing DOM.
    • Pro tip: If you use hydrate, React'll yell at you in the console if what's rendered from the server is different from what's expected.
  2. If you want to stop that render, you use (duh) shouldComponentUpdate.

NOTE: Check that pro tip out closely. If you mount React with hydrate (a v16 addition), it should yell at you if you don't have DOM that matches what React expects.

Second, um, don't change the name of your components' render calls to hydrate like my, um, my friend did. That's stupid. You hydrate only where you mount React:

//ReactDOM.render(<App />, document.getElementById('root'));
ReactDOM.hydrate(<App />, document.getElementById('root'));

The name of your render functions in your components will stay render.


Why does one use truly universal React?

Now even though I've learned to use the magic of renderToString, while I was searching up best SSR practices, I caught James Nelson's Universal React: You're doing it wrong, which referenced these tweets:

Dan Abramovโ€ย @dan_abramov
Replying toย @james_k_nelson

.@james_k_nelson Actually this isnโ€™t even the case. AFAIK Facebook is not currently using React server rendering.

5:19 PM - 20 Mar 2016

And this one:

Christoph Nakazawaโ€ย @cpojer
Replying toย @dan_abramov

@dan_abramov @james_k_nelson http://instagram.comย  uses server rendering for SEO. We haven't found sr useful for real users.

6:41 PM - 20 Mar 2016

For me, the quick take-home is this:

  1. Universal React wasn't worth the proverbial squeeze...
  2. ... in 2016.

I'd like to see updates on those. Does Instagram still use SSR? Does it think that's smart? Is SEO still enough of a use case for the overhead, especially now that at least Google's spider renders JavaScript? Is the SSR done with Universal React?

This also gives you a clue of where we might go for SSR -- not universal React.

Wait, what? Are you pondering what I'm pondering?

If they called them sad meals...

No no! I'm thinking we should look into doing SSR without React a little more closely.


SSR is just string manipulation

Look, SSR is the simplest thing you've ever read more than three articles about. At its core, it's just string manipulation. Let's look at a little node express code from the article I initially referenced:

// render the app as a string
const html = ReactDOMServer.renderToString(<App />);

// inject the rendered app into our html and send it
return res.send(
    htmlData.replace(
        '<div id="root"></div>',
        `<div id="root">${html}</div>`
    )
);

Follow that?

  1. Create a string to represent rendered content.
  2. Have an html page template for your react. (Nothing new here.)
  3. Replace the root element where you'd mount React and put your rendered html string in the middle.

It's that simple. You could use anything to create that html string, not just React running on Express. All that has to happen is that the content in html, once couched in the html page's template, mimics exactly what React would try to make when it renders OR, get this, you could write your React components in a way that they ignore the DOM from SSR and let the SSR'd DOM alone until state is changed on the client.

Make sense?

The most beautiful upshot of this "discovery" is that you can use any server you want for SSR.

Want to create your SSR content for a React SPA with C# and Razor?

Shia says, "Just do it!"

(It really isn't rocket science here -- the advantages of this approach are essentially tantamount to those when you used Apache in 1997. "Hey look! You want static text?! I can make you static text!" Or maybe more like using Classic ASP in 1997. "You want text generated from a database?!! You got text generated from a database!1!" Wow, man. Groovy.)

But I thought Universal was architecturally superior?

I really like the possibility of using the same language on the server as the client. There seem to be lots of obvious, inherent advantages. For one, you can write your business validation logic once, and reuse it on the client & server.

That's beautiful. For example, you almost get client-side validation "for free" when you write good server-side validation. And if I had a quarter for every time server-side validation on a project lagged behind the client (this is so wrong, folks. SOOOOO wrong), I'd have a few bucks.

But there is overhead in fully supporting universal React once you get past the first, obvious wins. And, truth be told, I've slowly moved off of doing any real validation client-side in all but the most network-starved use cases. I love JavaScript, but I'm practical enough to realize that thin clients are the best clients. Have your client ready to handle validation payloads from the server, but don't have any business logic client-side if you can help it.

Once you get past the proverbial Universal siren song and then also realize that SSR is really, at its core, simply what it says -- html rendered on the server-side, not necessarily html rendered with the same complex code as the client, now on the server -- you will finally have the most flexibility for composing the best, most performant React sites.


Random, somewhat related, somewhat timely reading: Redux - Not Dead Yet!

Labels: , , ,


posted by ruffin at 5/08/2018 03:37:00 PM
Thursday, April 26, 2018

Until recently, MarkUpDown had allowed you to paste copied HTML snippets into Markdown with all of the html styling retained using the not-so-discoverable shortcuts alt-v and, with quote, alt-shift-v).

This pasted those snippets into your Markdown with all of the HTML's CSS, making for the potentially neat situation where your quote was visibly very different from the rest of your page, preserving the look & feel of the page which provided your quote.

I quickly found that preserving colors could make for ugly pastes, and wrote some code to remove those styles, but otherwise, quotes would appear to be very similar to the original.

example quote styling

So not exact, but you can see the resemblance with the original:

quote in original context

But the code was also very ugly. There was so much CSS it started to ruin the whole "shorthand" nature of Markdown.

<p style="word-spacing: 0.05em; line-height: 1.6em; position: relative; z-index: 1; font-family: ‘Source Sans Pro’, ‘Helvetica Neue’, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration- ">Vue (pronounced /vjuห/, like<span>&nbsp;</span><strong style="font-weight: 600; ">view</strong>) is a<span>&nbsp;</span><strong style="font-weight: 600; ">progressive framework</strong><span>&nbsp;</span>for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is easy to pick up and integrate with other libraries or existing projects. On the other hand, Vue is also perfectly capable of powering sophisticated Single-Page Applications when used in combination with<span>&nbsp;</span><a href="https://vuejs.org/v2/guide/single-file-components.html" style="text-decoration: none; font-weight: 600;">modern tooling</a><span>&nbsp;</span>and<span>&nbsp;</span><a href="https://github.com/vuejs/awesome-vue#components–libraries" target="_blank" rel="noopener" style="text-decoration: none; font-weight: 600;">supporting libraries</a>.</p>

This html code was provided by Microsoft’s HTML Clipboard Format. The CSS dump above is, honestly, essentially exactly what I get from the clipboard’s garbled mess. Browsers seem to translate many classes into inline styles, and the clipboard format doesn’t do anything to normalize it.

(To the HTML Clipboard Format’s credit, however, you also get the original link, so that "From VueJS.org" link preceeding the quote is a "free" part of the "paste html as quote" action in MarkUpDown.)

Here’s the first p tag from that html again with some linebreaks…

<p
 style="word-spacing: 0.05em; line-height: 1.6em; position: relative; z-index: 1;
font-family: ‘Source Sans Pro’, ‘Helvetica Neue’, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; -webkit-text-stroke-width: 0px;
text-decoration-style: initial; text-decoration- ">

Good grief, right? You don’t want all that trash in your otherwise pretty clean Markdown, do you?

The first thing I tried was to pull all the styling out into classes that I’d put just north of the blockquote, making something like this…

<style>.q233941โ€“321 {word-spacing: 0.05em; line-height: 1.6em; position: relative; z-index: 1; font-family: โ€˜Source Sans Proโ€™, โ€˜Helvetica Neueโ€™, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; -webkit-text-stroke-width: 0px; text-decoration-style: initial;}

</style> > <p class="q233941โ€“321">Vue (pronounced /vjuห/, like โ€ฆ

I also started trying to normalize the classes and pull out shared settings when they overlapped so there wouldn’t be as much text before the blockquote. That was fun.

The classes route is better, at least once you get to the blockquote, but that’s still a lot of markup to inject into a markup shorthand. I didn’t like it.

So for now I’ve removed inline styles and classes from pastes, which I’m about to release. I don’t feel great about, but you do retain the markup, most importantly bold, italics, links, even images, which is a heck of a lot better than treating HTML as plain text. But it isn’t nearly as pretty to look at now.

I’m planning on bringing styles back under the "opt-in" settings under the "Beta Features" section of settings, but it’s hard to justify the overhead I’ve already spent on it. The Markdown stays cleaner now. That’s ultimately an improvement for a Markdown editor.

Oh well. Thus is the life of a utility author.

Labels: , , ,


posted by ruffin at 4/26/2018 01:22:00 PM
Monday, January 16, 2017

One of the interesting things about the MLK, Jr. spread on the Apple front page?

Apple's tribute to MLK, Jr.

The markup.

<article id="mlk-takeover" class="gallery-container" data-analytics-region="hero">
  <figure class="mlk-hero">
   <div class="mlk-image"></div>
   <div class="slide-content">
   <div class="copy-inner">
    <h1 class="quote">โ€œCommit yourself to the noble struggle for equal rights. You will make a greater person of yourself, a greater nation of your country, and a finer world to live in.โ€</h1>
    <span class="credit">Dr. Martin Luther King Jr.</span>
   </div>
   </div>
  </figure>
</article>

I wonder who else has had an data-analytics-region of "hero"?

Labels: ,


posted by ruffin at 1/16/2017 12:00:00 PM
Friday, October 14, 2016

Let's talk HTML Fragments in your clipboard when coding on Windows. I've created what's arguably the best Markdown editor on Win10 (if I do say so myself), and wanted it to be more intelligent when I was pasting content that comes from web browsers. That is, in the original version of MarkUpDown, if you copied the text I've got highlighted, below, from DaringFireball...

Quote from Walt Mossberg on Siri plus a little bit from Gruber, now with visible context menu saying "Copy"

... and you pasted it into MarkUpDown as a quotation (Ctrl-Shift-V), you'd get unstyled text, like this...

> Mossberg:
> For instance, when I asked Siri on my Mac how long it would take me to get to work, it said it didnโ€™t have my work address โ€” even though the โ€œmeโ€ contact card contains a work address and the same synced contact card on my iPhone allowed Siri to give me an answer.
> Similarly, on my iPad, when I asked what my next appointment was, it said โ€œSorry, Walt, somethingโ€™s wrongโ€ โ€” repeatedly, with slightly different wording, in multiple places on multiple days. But, using the same Apple calendar and data, Siri answered correctly on the iPhone.
> These sort of glaring inconsistencies are almost as bad as universal failures. The big problem Apple faces with Siri is that when people encounter these problems, they stop trying.

I mean, that's okay-ish. Unfortunately, you'd have to go put in an additional line after each line so that it's not all scrunched into one paragraph. And you lose that Gruber was block-quoting Mossberg. And you lose that "they stop trying" was originally in italics. That stinks.

Isn't Markdown really supposed to be shorthand for html? Can't we handle pasting html better than that?

Yes, yes we can...


TL;DR

Go pull the HtmlFragmentHelper, a working, in-progress library for turning HTML Fragment strings into view models with these properties...

public class HtmlFragmentViewModel
{
    public string Version = "";
    public int StartHtml = int.MinValue;
    public int EndHtml = int.MinValue;
    public int StartFragment = int.MinValue;
    public int EndFragment = int.MinValue;
    public string SourceUrl = "";
    public string FragmentSourceRaw = "";
    public string Error = "";

    //...
}

There are also several convenience methods to help you get, say, the top- and second-level domains for the HTML Fragment's source URL (example.com from http://blog.example.com/user/blog0000231.html), or just the html from the selected fragment (myHtmlFragmentViewModel.FragmentSourceParsed), etc.

Here's an example:

public string CreateQuote(string htmlFragmentSource) 
{
    string strIntroLink = string.Empty;
    HtmlFragmentViewModel vm = new HtmlFragmentViewModel(htmlFragmentSource);

    if (vm.SourceUrl.Length > 0 && vm.SourceUrlDomainSecondAndTopLevelsOnly.Length > 0)
    {
        strIntroLink = string.Format("From <a href=\"{0}\">{1}</a>:" + Environment.NewLine + Environment.NewLine,
            vm.SourceUrl, vm.SourceUrlDomainSecondAndTopLevelsOnly);
    }

    return strIntroLink + vm.FragmentSourceParsed;
}

Read how to use it here. Get it from GitHub, though the only file you really need is here.

And here's a quick article on how to get code back into the clipboard as html, which I'm not doing.


HTML Fragment Format

Want to paste clipboard HTML as HTML? Enter Microsoft's HTML clipboard format. Instead of using the standard code to read the clipboard's contents, like this...

string clipboardText = await Clipboard.GetContent().GetTextAsync();

... now you use this...

string htmlClipboardText = await Clipboard.GetContent().GetHtmlFormatAsync();

But when you look at the contents of htmlClipboardText, you quickly notice that strange things are afoot at the Circle K.

What number are you thinking of?

What comes back isn't a string with html source, but an "HTML Fragment" formatted string that looks like this:

HTML Fragment from Edge

Version:1.0
StartHTML:000000210
EndHTML:000003550
StartFragment:000002696
EndFragment:000003500
StartSelection:000002696
EndSelection:000003496
SourceURL:http://daringfireball.net/2016/10/mossberg_siri
<!DOCTYPE HTML>
<HTML lang="en"><HEAD>       <!-- Open Graph [jive] --> <!-- 
    <meta property="og:site_name"   content="Daring Fireball" />
    <meta property="og:title"       content="Walt Mossberg: โ€˜Why Does Siri Seem So Dumb?โ€™" />
    <meta property="og:url"         content="http://daringfireball.net/2016/10/mossberg_siri" />
    <meta property="og:description" content="In addition to the engineering hurdles to actually make Siri much better, Apple also has to overcome a โ€œboy who cried wolfโ€ credibility problem." />
    <meta property="og:image"       content="https://daringfireball.net/graphics/df-square-192" />
    <meta property="og:type"        content="article" />
 -->         <!-- Twitter Card [jive] -->                    <TITLE>Daring Fireball: Walt Mossberg: โ€˜Why Does Siri Seem So Dumb?โ€™</TITLE>        <LINK href="/graphics/apple-touch-icon.png" rel="apple-touch-icon-precomposed">     <LINK href="/graphics/favicon.ico?v=005" rel="shortcut icon">   <LINK href="/graphics/dfstar.svg" rel="mask-icon" color="#4a525a">  <LINK href="/css/fireball_screen.css?v1.7" rel="stylesheet" type="text/css" media="screen">     <LINK href="/css/ie_sucks.php" rel="stylesheet" type="text/css" media="screen">     <LINK href="/css/fireball_print.css?v01" rel="stylesheet" type="text/css" media="print">    <LINK href="/feeds/main" rel="alternate" type="application/atom+xml">   
<SCRIPT src="/mint/?js" type="text/javascript" async=""></SCRIPT>

<SCRIPT src="http://www.google-analytics.com/ga.js" type="text/javascript" async=""></SCRIPT>

<SCRIPT src="/js/js-global/FancyZoom.js" type="text/javascript"></SCRIPT>

<SCRIPT src="/js/js-global/FancyZoomHTML.js" type="text/javascript"></SCRIPT>
     <LINK title="Home" href="/" rel="home">     <LINK href="http://df4.us/pfz" rel="shorturl">  <LINK title="Apple Responds to Dash Controversy" href="http://daringfireball.net/2016/10/apple_dash_controversy" rel="prev">    
<SCRIPT src="http://daringfireball.net/mint/?record&amp;key=383950464d37374b39333637695970466458724e6779513431&amp;referer=&amp;resource=http%3A//daringfireball.net/2016/10/mossberg_siri&amp;resource_title=Daring%20Fireball%3A%20Walt%20Mossberg%3A%20%u2018Why%20Does%20Siri%20Seem%20So%20Dumb%3F%u2019&amp;resource_title_encoded=0&amp;window_width=1756&amp;window_height=921&amp;resolution=2438x1371&amp;flash_version=0&amp;1476397798179&amp;serve_js" type="text/javascript"></SCRIPT>
</HEAD><BODY onload="setupZoom()"><DIV id="Box"><DIV id="Main"><DIV class="article"><!--StartFragment--><P>Mossberg:</P><BLOCKQUOTE><P>For instance, when I asked Siri on my Mac how long it would take me to get to work, it said it didnโ€™t have my work address โ€” even though the โ€œmeโ€ contact card contains a work address and the same synced contact card on my iPhone allowed Siri to give me an answer.</P><P>Similarly, on my iPad, when I asked what my next appointment was, it said โ€œSorry, Walt, somethingโ€™s wrongโ€ โ€” repeatedly, with slightly different wording, in multiple places on multiple days. But, using the same Apple calendar and data, Siri answered correctly on the iPhone.</P></BLOCKQUOTE><P>These sort of glaring inconsistencies are almost as bad as universal failures. The big problem Apple faces with Siri is that when people encounter these problems, <EM>they stop trying</EM>.</P><!--EndFragment--></DIV></DIV></DIV></BODY></HTML>

Wow. No, really, wow. That surprised me. I was using Edge this time instead of Chrome, and whoa. Edge includes the entire page's header. That said, that's really not a horrible idea. We have really good context for this fragment, and if we wanted the original CSS, for example, we know where to get it.

Aside: Look at the info DaringFireball's sucking in:

resolution=2560x1440&amp;
flash_version=0&amp;
1476452395012&amp;
serve_js

Gruber doesn't use Flash. Kinda Panopticlicky, ain't it? Looks like it's supporting this.

Another Aside: Internet Explorer 11 creates the same fragment source, so if you think Edge was created from the ground up...

Interestingly, the old Internet Explorer copyright box used to reference Mosaic, but that's gone in IE11. Wonder if IE11 is really the child of IE6 and 7? But enough aside-ing...

HTML Fragment from Chrome

But let's take a look at where I initially started, with Chrome.

Version:0.9
StartHTML:0000000164
EndHTML:0000002719
StartFragment:0000000200
EndFragment:0000002683
SourceURL:http://daringfireball.net/2016/10/mossberg_siri
<html>
<body>
<!--StartFragment--><p style="margin: 0px 0px 1.6em; padding: 0px; color: rgb(238, 238, 238); font-family: Verdana, &quot;Bitstream Vera Sans&quot;, sans-serif; font-size: 11px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(74, 82, 90);">Mossberg:</p><blockquote style="font-size: 11px; margin: 2em 2em 2em 1em; padding: 0px 0.75em 0px 1.25em; border-left: 1px solid rgb(119, 119, 119); border-right: 0px solid rgb(119, 119, 119); outline: 0px; vertical-align: baseline; background: rgb(74, 82, 90); color: rgb(238, 238, 238); font-family: Verdana, &quot;Bitstream Vera Sans&quot;, sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-t
ransform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><p style="margin: 0px 0px 1.6em; padding: 0px;">For instance, when I asked Siri on my Mac how long it would take me to get to work, it said it didnโ€™t have my work address โ€” even though the โ€œmeโ€ contact card contains a work address and the same synced contact card on my iPhone allowed Siri to give me an answer.</p><p style="margin: 0px 0px 1.6em; padding: 0px;">Similarly, on my iPad, when I asked what my next appointment was, it said โ€œSorry, Walt, somethingโ€™s wrongโ€ โ€” repeatedly, with slightly different wording, in multiple places on multiple days. But, using the same Apple calendar and data, Siri answered correctly on the iPhone.</p></blockquote><p style="margin: 0px 0px 1.6em; padding: 0px; color: rgb(238, 238, 238); font-family: Verdana, &quot;Bitstream Vera Sans&quot;, sans-serif; font-size: 11px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacin
g: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(74, 82, 90);">These sort of glaring inconsistencies are almost as bad as universal failures. The big problem Apple faces with Siri is that when people encounter these problems,<span class="Apple-converted-space">ย </span><em>they stop trying</em>.</p><!--EndFragment-->
</body>
</html>

See the difference? Chrome's fragment initially looks much more focused, but also provides much less information about the code's original context. Worse, Chrome's puts all the CSS information inline, and repeating each CSS property inside of each pasted html element makes the source a long ways away from DRY. And that out-of-context, inline CSS is lossily translated, which will cause us some rendering problems that we'll see and discuss in a bit.

Original Source

Now Edge's fragment isn't perfect. Here's the original html of that snippet straight from the server...

<p>Mossberg:</p>

<blockquote>
  <p>For instance, when I asked Siri on my Mac how long it would take
me to get to work, it said it didnโ€™t have my work address &#8212;
even though the โ€œmeโ€ contact card contains a work address and
the same synced contact card on my iPhone allowed Siri to give
me an answer.</p>

<p>Similarly, on my iPad, when I asked what my next appointment was,
it said โ€œSorry, Walt, somethingโ€™s wrongโ€ &#8212; repeatedly, with
slightly different wording, in multiple places on multiple days.
But, using the same Apple calendar and data, Siri answered
correctly on the iPhone.</p>
</blockquote>

<p>These sort of glaring inconsistencies are almost as bad as universal failures. The big problem Apple faces with Siri is that when people encounter these problems, <em>they stop trying</em>.

NOTE: There's no closing </p> tag because I've cut the source at that spot.

Look how clean the original is! Why can't we just get that? Chrome's CSS injections and line flattening makes for a much less human readable snippet.

Edge is close, but still weird. Take another look. For some reason, Edge's fragment makes every tag uppercase like it's 1998. It also trashes Gruber's original (and thoughtful) whitespace. Also yuck. I mean, Gruber's using Markdown to write Daring Fireball. In a perfect world, I'd take that clipboard's html and turn it back into Markdown when it's pasted into MarkUpDown.

How do we get this original source?

Start and End Fragment

The important thing to catch is that the HTML Fragment format almost always includes a full html doc with html and body tags after the SourceURL and other metadata. Within that html code, there are markers, <!--StartFragment--> and <!--EndFragment-->, saying where the exact selection started and stopped.

Though Chrome immediately dives into your selected text (the "true" html fragment) immediately after the <body> tag, Edge gives you any open tags that come before your fragment too. In this case, you had three open div tags when you got to the highlighted selection: <DIV id="Box"><DIV id="Main"><DIV class="article">. Knowing this DOM could be really helpful if you were interested in retrieving the original CSS and formatting your fragment as close to the original markup as possible.

If you ignore context like this, though, it's an easy enough feat to take the string and parse out the "true fragment's" html by splitting the entire HTML Fragment string on <!--StartFragment--> and <!--EndFragment-->. Here's an early version of something I wrote to just take out the html, ignoring all the fragment metadata.

private string _parseHtmlClipboardFragment(string rawFragmentSource)
{
    string ret = rawFragmentSource;
    string delimiterStartAfter = "<!--StartFragment-->";
    string delimiterEndBefore = "<!--EndFragment-->";

    if (-1 < ret.IndexOf(delimiterStartAfter))
    {
        ret = ret.Substring(ret.IndexOf(delimiterStartAfter) + delimiterStartAfter.Length);
        if (-1 < ret.IndexOf(delimiterEndBefore))
        {
            ret = ret.Substring(0, ret.IndexOf(delimiterEndBefore));
        }
        else
        {
            ret = string.Empty;  // No luck, Ending not after Start; go back to nothing.
        }
    }

    return ret;
}

NOTE: I've got a nice library that parses all this up into a custom html fragment view model that I mentioned in TL;DR. I wouldn't and don't use the above code in most cases.

When we parse out that html and insert it into our Markdown from Chrome, however, we get some, um, interesting results.

NOTE: Remember that Markdown is a superset, so to speak, of html. You could have a "Markdown" file without any Markdown syntax that's pure html. So what I'm really saying is, "Let's see what those html snippets that we pulled from the fragment look like when they're injected into our regularly scheduled html."

I'm going to wrap these pastes in blockquote tags so that you can tell where they start and stop easily.

Edge Parsed Code

Mossberg:

For instance, when I asked Siri on my Mac how long it would take me to get to work, it said it didnโ€™t have my work address โ€” even though the โ€œmeโ€ contact card contains a work address and the same synced contact card on my iPhone allowed Siri to give me an answer.

Similarly, on my iPad, when I asked what my next appointment was, it said โ€œSorry, Walt, somethingโ€™s wrongโ€ โ€” repeatedly, with slightly different wording, in multiple places on multiple days. But, using the same Apple calendar and data, Siri answered correctly on the iPhone.

These sort of glaring inconsistencies are almost as bad as universal failures. The big problem Apple faces with Siri is that when people encounter these problems, they stop trying.

Though you should remember that the original source has been smeared together, losing its newlines, and all the tags are strangely capitalized, the source looks pretty nice. It's plain, and adopts the local styling for the most part, but the most important markup is still there -- the blockquote, the italics, links if they'd been included, etc.

Chrome Parsed Code

Mossberg:

For instance, when I asked Siri on my Mac how long it would take me to get to work, it said it didnโ€™t have my work address โ€” even though the โ€œmeโ€ contact card contains a work address and the same synced contact card on my iPhone allowed Siri to give me an answer.

Similarly, on my iPad, when I asked what my next appointment was, it said โ€œSorry, Walt, somethingโ€™s wrongโ€ โ€” repeatedly, with slightly different wording, in multiple places on multiple days. But, using the same Apple calendar and data, Siri answered correctly on the iPhone.

These sort of glaring inconsistencies are almost as bad as universal failures. The big problem Apple faces with Siri is that when people encounter these problems,ย they stop trying.

Um, ew. Wha' happen'd?

Unfortunately, even though Daring Fireball's entire page has the same styles applied, this inline kludge Chrome performs puts it only in each, in this case, <p> tag. So when we have a margins around paragraphs, there's nothing telling us to also put that color and style between the block-level tags. There's no surrounding tag to be a stand-in for, essentially, the body (or any other lost, open) tag.

Let's look at all the overhead we have for each p from that fragment:

<p style="
    margin: 0px 0px 1.6em;
    padding: 0px;
    color: rgb(238, 238, 238);
    font-family: Verdana, &quot;Bitstream Vera Sans&quot;, sans-serif;
    font-size: 11px;
    font-style: normal;
    font-variant-ligatures: normal;
    font-variant-caps: normal;
    font-weight: normal;
    letter-spacing: normal;
    orphans: 2;
    text-align: left;
    text-indent: 0px;
    text-transform: none;
    white-space: normal;
    widows: 2;
    word-spacing: 0px;
    -webkit-text-stroke-width: 0px;
    background-color: rgb(74, 82, 90);
">

And here's what we have from Chrome's Dev Tools' "Computed" style tab:

color: rgb(238, 238, 238);
display: block;
font-family: Verdana, "Bitstream Vera Sans", sans-serif;
font-size: 11px;
height: 19px;
line-height: 19.8px;
margin-bottom: 17.6px;
margin-left: 0px;
margin-right: 0px;
margin-top: 0px;
padding-bottom: 0px;
padding-left: 0px;
padding-right: 0px;
padding-top: 0px;
text-align: left;
text-size-adjust: 100%;
width: 425px;
-webkit-margin-after: 17.6px;
-webkit-margin-before: 0px;
-webkit-margin-end: 0px;
-webkit-margin-start: 0px;

But note that that's essentially all from one css file, as properties from user agent stylesheets are simply the browser's defaults:

Paragraph styles for Daring Fireball

If you'd like, we can compare the fragment's CSS vs. the stylesheet. Spoiler: It's a mess. Not a lot of matching. Click here to see. Ugly.

The bottom line is that background-color: rgb(74, 82, 90); is something that belongs to the body, but is inserted here by Chrome into its HTML Clipboard contents as something that's attached to each block element. That's wrong. It doesn't display correctly, and it needlessly clutters the resulting HTML.

With HtmlFragmentHelper, I have a couple of choices. One is to strip all inline styles out, or at least some subset of styling. If I want to maintain as much of the original as possible, I might just blast anything that injects colors into the html, like color and background-color. Or I could blast all the inline style info and get something more like Edge's code.

Or I could normalize the CSS and optionally (via a property on HtmlFragmentViewModel) wrap it all in a block-level tag that contains CSS that's everywhere. Or at least in all of the top-level tags. But now I'm starting to write an html parser, which is a little outside of my current scope.

I think I'm going to do the former, though it's not in there as of this writing. That Chrome paste looks horrible as is, though. If only there was an easier way...


HTML Fragment from Firefox

There are certainly other applications that create HTML Clipboard values. I ran into LibreOffice's when using Calc, their spreadsheet app, and its html clipboard doesn't include Start and EndFragment tags. Wonderful, folks, wonderful.

But isn't there one glaring omission I might want to add here? You know, I think there is at least one...

For fun, let's take a look at Firefox's fragment too. Firefox isn't as popular as it used to be, but it's probably worth taking a look. (Remember that this is all on Windows, and Safari is dead enough by now that I'm not going to bother with v5.)

Version:0.9
StartHTML:00000156
EndHTML:00001060
StartFragment:00000190
EndFragment:00001024
SourceURL:http://daringfireball.net/2016/10/mossberg_siri
<html><body>
<!--StartFragment--><p>Mossberg:</p>

<blockquote>
  <p>For instance, when I asked Siri on my Mac how long it would take
me to get to work, it said it didnโ€™t have my work address โ€”
even though the โ€œmeโ€ contact card contains a work address and
the same synced contact card on my iPhone allowed Siri to give
me an answer.</p>

<p>Similarly, on my iPad, when I asked what my next appointment was,
it said โ€œSorry, Walt, somethingโ€™s wrongโ€ โ€” repeatedly, with
slightly different wording, in multiple places on multiple days.
But, using the same Apple calendar and data, Siri answered
correctly on the iPhone.</p>
</blockquote>

<p>These sort of glaring inconsistencies are almost as bad as universal 
failures. The big problem Apple faces with Siri is that when people 
encounter these problems, <em>they stop trying</em>.</p><!--EndFragment-->
</body>
</html>

Oh, so beautiful. Same whitespace as the original, with the added bonus (?) that the final paragraph is also text wrapped. No crazy inline CSS attempted. No header overhead or 1998-style HTML TAGS.

You could argue that Chrome is better because it has that inline CSS (yuck!) or Edge because it has the full page headers, but honestly, we're only one step farther away from what Edge gave us. We have the URL here. If we have network access to get CSS, we have network access to read the header and figure out where the CSS lives ourselves. Don't overcomplicate things. Beautiful. Good looking code continues to look good when pasted inline with Markdown.

Firefox Parsed Code

And Firefox's snippet is just as nice when pasted.

Mossberg:

For instance, when I asked Siri on my Mac how long it would take me to get to work, it said it didnโ€™t have my work address โ€” even though the โ€œmeโ€ contact card contains a work address and the same synced contact card on my iPhone allowed Siri to give me an answer.

Similarly, on my iPad, when I asked what my next appointment was, it said โ€œSorry, Walt, somethingโ€™s wrongโ€ โ€” repeatedly, with slightly different wording, in multiple places on multiple days. But, using the same Apple calendar and data, Siri answered correctly on the iPhone.

These sort of glaring inconsistencies are almost as bad as universal failures. The big problem Apple faces with Siri is that when people encounter these problems, they stop trying.

I miss Firefox.

Labels: , , , , , , ,


posted by ruffin at 10/14/2016 11:46:00 AM
Tuesday, April 19, 2016

Sometimes, code smell comes from your documentation:

In some case, the browser will keep suggesting autocompletion values even if the autocomplete attribute is set to off. This unexpected behavior can be quite puzzling for developers. The trick to really force the no-completion is to assign a random string to the attribute like so:

autocomplete="nope"

Since this random value is not a valid one, the browser will give up.

Giving invalid data until "the browser will give up" is a best practice, is it? Whew, that smells. I love the, "The trick is to really force" line. "Really force"?

"Hey, Firefox, remember when I told you to turn off autocomplete? It's just an informal request. If I want you to really honor it, I'll really force you to."

/sigh

Protip for Mozilla: Firefox form autocomplete is broken. I don't really care if it follows standards; most users and nearly every web developer will tell you its behavior is broken.

I hate to see [sic] it, but it looks like Firefox usage may be down over 12% over 2015. It was my favorite browser to use for dev and home. I think the trend is pretty clear: There are now only three browsers. Edge/IE on Windows, Safari on iOS (and OS X, if you count it), and Chrome.

Labels: ,


posted by ruffin at 4/19/2016 10:56:00 AM
Wednesday, April 06, 2016

The Apple TV remote apparently underwent a change in the most recent update. Used to be that you could just touch the Apple TV remote's trackpad, and you started tracking. Not so any longer. That just pops up a little hint that if you fully click the pad you'll jump forward or back 10 seconds, depending on where your finger is.

Annoying. I couldn't find a quick workaround, so I was telling Siri, "Fast forward 15 minutes," and "Rewind 20 mins". What a freaking pain.

(Here's the Siri fail.)

They set me up with a phone call, which is to say they routed me to a web page where I set up a phone call.

The call went well, actually. Tara (?) knew exactly what I was talking about, and had had the same think happen to her with her Apple TV. "I am in Netflix, in case that matters." "No, what do you think I'm doing when I get home? Exactly that."

The answer was to pause what you're watching. Then, and only then, will you be able to use the "Touch Surface Tracking".

Anyhow, long story a touch shorter, check out the spacing in this survey form I was sent to fill out the next day:

apple survey spacing is exceptionally spread out

Wow. Just wow.[1] Check out that "Next" button down at the bottom. Do designers not get to use this on 27" iMacs? I mean, I like things that work on lowest common denominator, but shouldn't somebody test in a larger monitor?

Finding the culprit wasn't too difficult.

web inspector of Apple survey page

<div class="survey" id="survey" style="min-height: 1008px;">
               <div class="surveybox">
                    <noscript>&amp;lt;style&amp;gt;html{display:none;}&amp;lt;/style&amp;gt;&amp;lt;meta http-equiv="refresh" content="0; url=https://survey.apple.com/efm/survey?s=3D3148E443305DE208D35D82693FAEBF74&amp;amp;jsrequired=1"&amp;gt;</noscript>
<form name="PdcSurvey" action="https://survey.apple.com/efm/survey" onreset="return survey.OnReset();" onsubmit="return PdcProcessPage();" method="post" novalidate="">

  <!--Q24_START-->
  <div class="survey-content" style="min-height: 960;"><div id="Q24_WRAPPER" class="question essay">
    <a class="anchor" name="A24" id="A24"></a><label class="question-text" for="Q24">What could we have done better to improve your AppleCare support experience?</label>
    <div class="response-set">
...

See that hard-coded style="min-height: 1008px;"? If not, perhaps you found the style="min-height: 960px;" a few divs later?

Ouch. That's not what you want. Just change those two to 200 and 180 and you get...

more sensible spacing example

I know, I know, now there's the chance that some pages are taller than others. You can either make the original pane as large as you need for your busiest screen (not great, unless you're careful with how big the UI gets or scroll for questions that are exceptionally long), or you could just move the Next and Submit buttons to the top of the page and let it bounce from frame to frame. You can argue that these two alternatives are wrong for whatever reason, and I'm sure there's a better option, but it'd be hard to argue what they have right now is right.

Ouch.

I mean, I know they have good people at Apple. I recall looking at the source in iCloud once to see how they were doing their calendar and seeing a hidden job advert with an ASCII art cloud with a smiley face in it. Now it looks like they're removed it, but that's a cute touch, and the web version of Calendar is actually pretty good. Ask me, I'd know. If I'd been willing to move to CA right now, I would've applied.


[1] Yes, this from a guy whose blog has been hard-coded to 600px seemingly since the invent of the Internet.

Labels: , , ,


posted by ruffin at 4/06/2016 12:07:00 PM
Wednesday, March 02, 2016

Sometimes, experience does bite you, if only gently. I've still been using name attributes in links to create "hash" links (http://www.example.com/index.html#goHere). That's, um, reasonably close to wrong:

The use of <a name ...> is declared as obsolete in HTML5 CR, and it really reflects the shortcomings of early HTML versions. โ€“ Jukka K. Korpela Dec 13 '13 at 14:09

@JukkaK.Korpela I wasn't aware of that. Has just using IDs of elements (e.g. divs) replaced it? Or is there some other mechanism? โ€“ kfb Dec 13 '13 at 14:20

Using id attributes is the recommended way (and has been possible for a long time, all relevant browsers support it). โ€“ Jukka K. Korpela Dec 13 '13 at 14:28

I often look through html to find a good name attribute to link more directly to something I find interesting. Looks like that'll be lots easier now. Phew.

Labels: ,


posted by ruffin at 3/02/2016 09:35:00 AM
Wednesday, June 17, 2015

That tab separated values to ASCII (and Unicode) table-like structures generator is here. And here's the sauce of that link (for me, at least).

Particularly useful for StackOverflow.

Labels: , ,


posted by ruffin at 6/17/2015 02:19:00 PM
Thursday, May 28, 2015

While reading up on how to properly respond to Accept-Encoding:gzip requests with a quick node server I'm hacking up, I ran into this support article about IE6:

In Internet Explorer, the Urlmon.dll file uses an internal buffer to read compressed data. Urlmon.dll fills this buffer when more data arrives and empties the buffer when Urlmon's client, Mshtml, reads data. The bytes that remain to be decoded in the buffer may be small (8 bytes or less) and the data contained in the buffer decompresses to 0 bytes. Frequently, this data is gzip frame data. When Mshtml receives 0 bytes, it thinks that all the data is read and closes the data stream. As a result, the HTML page sometimes appears truncated.

No, I'm not saying you necessarily need to code around the foibles of a now [thankfully] fairly rare version of IE.

What I am saying is that this is a rookie mistake that made it out of QA at one of the best software engineering companies (particularly in 2002-2003) there is, and in one of its marquee products. Anyone who has used streams has run into issues with buffers similar to this one. This is, at worst, a slight variation on theme.

Though I'm not suggesting you forgive bad code either, it is slightly comforting to know that, at least 12 years ago, Microsoft let something so [okay, potentially anachronistically] glaring slip.

Labels: , , , ,


posted by ruffin at 5/28/2015 09:12:00 AM
Friday, October 19, 2012

It's help doc time at the end of a project, boys and girls, and reading through our existing docs after adding pages for the stuff I'd just programmed I found a page where an image was described in the text as an imagemap, but it wasn't.

After the requisite Googling for an html imagemap on OS X and only finding a few pay-to-play examples, I thought, "The GIMP should do this, right?"

It does.
 
14. Web Filters
14.2. ImageMap

I should make a video tutorial that's a little more straightforward than this written one, but it's a great tool.  GIMP as a whole is a little slow on OS X imo, but this tool is complete money.  Make circle, quadrangles, or any multipoint poly, save your imagemap to a text file, edit points easily, and load and reedit the thing later.

Filters >>> Web >>> Imagemap.  Voila.

It's essentially perfect.  Thanks Maurits Rijk, and yes, I left the HTML comment in the page.

Labels: , ,


posted by ruffin at 10/19/2012 10:21:00 AM
Wednesday, October 17, 2012

No, seriously. WYSisn'tWYG, you can't [obviously] edit CSS files directly, you can't insert images into folders via the OS and have RoboHelp realize they're there, it puts the images it does import into the project's root folder by default, its editor st1nk0rz, and it's carp [sic].
Seriously. A big, giant, floppy piece of carp. I'm willing to use it temporarily on the assumption that folks who usually write help on this particular project need the hand-holding, but I feel like I'm in a fight with my hands tied behind my back.

Labels: , ,


posted by ruffin at 10/17/2012 09:52:00 AM
Thursday, March 25, 2010

If there's one thing that I know Jobs would like to have back, it's an Apple computing platform with tightly controlled access for developers. As the Wall Street Journal apparently reports (via AppleInsider): "Jobs has kept 'tight control and directors have rarely challenged him.'" His preferred dev environment is no different. Right now, on the Macintosh, anyone can code up an app and release it without so much as Googling (Binging?) the Apple Human (once User) Interface Guidelines. Heck, even I've released apps for the Mac into the wild. Oh noes!!!

Oh wait, Jobs has gotten that closed development environment, hasn't he? It's the iPod, iPhone, and, increasingly overlapping with the Mac, the iPad:

In February, it was rumored that Hulu, an online streaming video destination for multiple networks, plans to make its videos available without Flash for the iPad platform. Reports then alleged that the Web site could be prepared by the time the iPad launches April 3, though it was said the service would likely be subscription only.


If the iPad only does HTML5/H.264 jive, the fact that this protocol isn't the most popular on the net gives it a leg up on open browsers. That is, if Hulu makes HTML5 pay to play only, thanks to the iPad's effectively closed platform, Hulu has a ready-made, similarly closed/captive market.

* If the iPad did Flash, not only would there be a closed system involved that Apple doesn't control, but there'd be no easy way to differentiate folks using the iPad platform. Goodbye Hulu revenue stream.

*With no Flash, Hulu has a reason to partner/get in bed with/come to the defense of Apple's iPad and to temper its support of Adobe's Flash
.

Captive markets are exactly what Jobs likes to have (see the iPhone developer program and the rules for distributing software, where Apple can even, 1984-style, rip programs off of your iPhone retroactively!), at least until he gets to the point that market dominance (digital music) makes it so that captivity works against Apple selling hardware. So once the iPod and the iTunes Music Store dominate digital music, Jobs makes DRM leave the stage precisely to ensure there are no competitors to the gorilla.

But, again, the interesting point here is how Apple is reinventing the Mac. As the iPod stretches out and begins to swallow the Macintosh via the iPhone and now iPad, it's essential to pay attention to the compromises these [at least relatively] closed platforms are making. The iPad will do 50% of what I use my MacBook for and essentially 90% of what I use my iPod touch for (the balance being "fitting my pocket"). But I can't run my Java apps on my iPad, and probably never will, and certainly won't without Jobs' permission.

(Yes, I realize Apple develops and maintains the standard Mac JVM, but there are others that work on OS X. Don't split hairs, please. ;^D)

Labels: , , , , , , , , , ,


posted by ruffin at 3/25/2010 10:01:00 AM
Saturday, November 14, 2009

Finally dug up an easy enough AJAX sample, and thought I'd share my slight variation on theme. If you put these two files into a dir on a webserver, you can play around a bit with the URL you're calling (URL isn't really a URL and must be relative -- calling off-site URLs seems to cause some security issue where you keep getting nothing back) and what you expect to find in the querystring and post vars. Once you've got this running, you're pretty much raring to go with AJAX. Many examples have more error checking, which would likely be useful, but this is working so I'm going with it for now.

ajax.php
<html>
<head>
<title>Simple Ajax Example</title>
<script language="Javascript">
function xmlhttpPost(strURL) {
var xmlHttpReq = false;
var self = this;
// Mozilla/Safari
if (window.XMLHttpRequest) {
self.xmlHttpReq = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject) {
self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
self.xmlHttpReq.open('POST', strURL, true);
self.xmlHttpReq.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
updatepage(self.xmlHttpReq.responseText);
}
}
self.xmlHttpReq.send(getquerystring());
}

function getquerystring() {
var form = document.forms['f1'];
var word = form.word.value;
qstr = 'w=' + escape(word); // NOTE: no '?' before querystring
return qstr;
}

function updatepage(str){
document.getElementById("result").innerHTML = str;
}
</script>
</head>
<body>
<form name="f1">
word: <input name="word" value="willBeInPOST" type="text"><br>
url: <input name="url" value="ajaxCatch.php?foo=bar" type="text"><br>

<!-- input value="Go" type="button"
onclick='JavaScript:xmlhttpPost("/cgi-bin/simple-ajax-example.cgi")'></p -->
<input value="Go" type="button"
onclick="xmlhttpPost(document.forms[0].elements['url'].value)"></p>
<div id="result"></div>
</form>
</body>
</html>




ajaxCatch.php
<html>
<head>
<title>Simple Ajax Example</title>
</head>
<body>
Test<br>
<?php
foreach ($_GET as $key => $value) {
$querystring .= $key."=".$value;
}
echo $querystring . "<br>";
foreach ($_POST as $key => $value) {
$strPost .= $key."=".$value;
}
echo $strPost . "<br>";
?>
</body>
</html>

Labels: , , ,


posted by ruffin at 11/14/2009 10:51:00 PM

<< Older | Newer >>


Support freedom
All posts can be accessed here:


Just the last year o' posts:

URLs I want to remember:
* Atari 2600 programming on your Mac
* joel on software (tip pt)
* Professional links: resume, github, paltry StackOverflow * Regular Expression Introduction (copy)
* The hex editor whose name I forget
* JSONLint to pretty-ify JSON
* Using CommonDialog in VB 6 * Free zip utils
* git repo mapped drive setup * Regex Tester
* Read the bits about the zone * Find column in sql server db by name
* Giant ASCII Textifier in Stick Figures (in Ivrit) * Quick intro to Javascript
* Don't [over-]sweat "micro-optimization" * Parsing str's in VB6
* .ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); (src) * Break on a Lenovo T430: Fn+Alt+B
email if ya gotta, RSS if ya wanna RSS, (?_?), ยข, & ? if you're keypadless


Powered by Blogger etree.org Curmudgeon Gamer badge
The postings on this site are [usually] my own and do not necessarily reflect the views of any employer, past or present, or other entity.