code:
<?php

/**
 * Tests of the parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2;
use Mf2\Parser;
use PHPUnit_Framework_TestCase;

class ParsePTest extends PHPUnit_Framework_TestCase {

	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	/**
	 * @group parseP
	 */
	public function testParsePHandlesInnerText() {
		$input = '

Example User

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Example User', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @group parseP
	 */
	public function testParsePHandlesImg() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Example User', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @group parseP
	 */
	public function testParsePHandlesAbbr() {
		$input = '
@example
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Example User', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @group parseP
	 */
	public function testParsePHandlesData() {
		$input = '
<data class="p-name" value="Example User"></data>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Example User', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @group parseP
	 */
	public function testParsePHandlesDataWithBlankValueAttribute() {
		$input = '
<data class="p-name" value="">Example User</data>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @group parseP
	 */
	public function testParsePReturnsEmptyStringForBrHr() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('', $output['items'][0]['properties']['name'][0]);
		$this->assertEquals('', $output['items'][0]['properties']['name'][0]);
	}

	public function testParsesInputValue() {
		$input = '<input class="u-url" value="http://example.com" />';
		$result = Mf2\parse($input);
		$this->assertEquals('http://example.com', $result['items'][0]['properties']['url'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/53
	 * @see http://microformats.org/wiki/microformats2-parsing#parsing_an_e-_property
	 */
	public function testConvertsNestedImgElementToAltOrSrc() {
		$input = <<<EOT

The day I saw a

Blah blah

EOT;
		$result = Mf2\parse($input, 'http://waterpigs.co.uk/articles/five-legged-elephant');
		$this->assertEquals('The day I saw a five legged elephant', $result['items'][0]['properties']['name'][0]);
		$this->assertEquals('Blah blah http://waterpigs.co.uk/photos/five-legged-elephant.jpg', $result['items'][0]['properties']['summary'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/69
	 */
	public function testBrWhitespaceIssue69() {
		$input = '

Street Name 9
12345 NY, USA

';
		$result = Mf2\parse($input);

		$this->assertEquals('Street Name 9' . "\n" . '12345 NY, USA', $result['items'][0]['properties']['adr'][0]);
		$this->assertEquals('Street Name 9', $result['items'][0]['properties']['street-address'][0]);
		$this->assertEquals('12345 NY, USA', $result['items'][0]['properties']['locality'][0]);
		// p-name is no longer implied for this test due to other p-*
		// see https://github.com/microformats/microformats2-parsing/issues/6
		$this->assertArrayNotHasKey('name', $result['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/89
	 */
	public function testEmptyAlt() {
		$input = '
mention.tech
';
		$result = Mf2\parse($input);

		$this->assertEquals('mention.tech', $result['items'][0]['properties']['org'][0]);
		$this->assertEquals('mention.tech', $result['items'][0]['properties']['name'][0]);
	}

}


code:
<?php
/**
 * Tests of the parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2;
use Mf2\Parser;
use PHPUnit_Framework_TestCase;

class ParseUTest extends PHPUnit_Framework_TestCase {
	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesA() {
		$input = '
Awesome example website
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com', $output['items'][0]['properties']['url'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesEmptyHrefAttribute() {
		$input = '
Awesome example website
';
		$parser = new Parser($input, "http://example.com/");
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][0]['properties']['url'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesMissingHrefAttribute() {
		$input = '
Awesome example website
';
		$parser = new Parser($input, "http://example.com/");
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/Awesome example website', $output['items'][0]['properties']['url'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesImg() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/someimage.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesArea() {
		$input = '
<area class="u-photo" href="http://example.com/someimage.png"></area>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/someimage.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesObject() {
		$input = '
<object class="u-photo" data="http://example.com/someimage.png"></object>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/someimage.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesAbbr() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/someimage.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesAbbrNoTitle() {
		$input = '
no title attribute
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('no title attribute', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesData() {
		$input = '
<data class="u-photo" value="http://example.com/someimage.png"></data>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/someimage.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group baseUrl
	 */
	public function testResolvesRelativeUrlsFromDocumentUrl() {
		$input = '

';
		$parser = new Parser($input, 'http://example.com/things/more/more.html');
		$output = $parser->parse();

		$this->assertEquals('http://example.com/things/image.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group baseUrl
	 */
	public function testResolvesRelativeUrlsFromBaseUrl() {
		$input = '<base href="http://example.com/things/more/andmore/" />

';
		$parser = new Parser($input, 'http://example.com/things/more.html');
		$output = $parser->parse();

		$this->assertEquals('http://example.com/things/more/image.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group baseUrl
	 */
	public function testResolvesRelativeUrlsInImpliedMicroformats() {
		$input = '';
		$parser = new Parser($input, 'http://example.com/things/more.html');
		$output = $parser->parse();

		$this->assertEquals('http://example.com/things/image.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group baseUrl
	 */
	public function testResolvesRelativeBaseRelativeUrlsInImpliedMicroformats() {
		$input = '<base href="things/"/>';
		$parser = new Parser($input, 'http://example.com/');
		$output = $parser->parse();

		$this->assertEquals('http://example.com/things/image.png', $output['items'][0]['properties']['photo'][0]);
	}

	/** @see https://github.com/indieweb/php-mf2/issues/33 */
	public function testParsesHrefBeforeValueClass() {
		$input = 'WRONG';
		$result = Mf2\parse($input);
		$this->assertEquals('http://example.com/right', $result['items'][0]['properties']['url'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesAudio() {
		$input = '
<audio class="u-audio" src="http://example.com/audio.mp3">
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('audio', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/audio.mp3', $output['items'][0]['properties']['audio'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesVideo() {
		$input = '
<video class="u-video" src="http://example.com/video.mp4"></video>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('video', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/video.mp4', $output['items'][0]['properties']['video'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesVideoNoSrc() {
		$input = '
<video class="u-video">no video support</video>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('video', $output['items'][0]['properties']);
		$this->assertEquals('no video support', $output['items'][0]['properties']['video'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesSource() {
		$input = '
<video><source class="u-video" src="http://example.com/video.mp4" type="video/mp4"><source class="u-video" src="http://example.com/video.ogg" type="video/ogg"></video>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('video', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/video.mp4', $output['items'][0]['properties']['video'][0]);
		$this->assertEquals('http://example.com/video.ogg', $output['items'][0]['properties']['video'][1]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesVideoPoster() {
		$input = '
<video class="u-photo" poster="http://example.com/posterimage.jpg"><source class="u-video" src="http://example.com/video.mp4" type="video/mp4"></video>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('video', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/video.mp4', $output['items'][0]['properties']['video'][0]);
		$this->assertEquals('http://example.com/posterimage.jpg', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUWithSpaces() {
		$input = '
Awesome example website
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com', $output['items'][0]['properties']['url'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/130
	 */
	public function testImpliedUWithEmptyHref() {
		$input = 'Jane Doe
<area class="h-card" href="" alt="Jane Doe"/ >

Jane Doe

<area href="">Jane Doe</area>

Jane Doe

';
		$parser = new Parser($input, 'http://example.com');
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][0]['properties']['url'][0]);

		$this->assertArrayHasKey('url', $output['items'][1]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][1]['properties']['url'][0]);

		$this->assertArrayHasKey('url', $output['items'][2]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][2]['properties']['url'][0]);

		$this->assertArrayHasKey('url', $output['items'][3]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][3]['properties']['url'][0]);

		$this->assertArrayHasKey('url', $output['items'][4]['children'][0]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][4]['children'][0]['properties']['url'][0]);
	}

  public function testValueFromLinkTag() {
    $input = <<< END
<!doctype html>

    <link rel="canonical" class="u-url p-name" href="https://example.com/" title="Example.com homepage">

END;

    $parser = new Parser($input, 'https://example.com');
    $output = $parser->parse();

    $this->assertArrayHasKey('url', $output['items'][0]['properties']);
    $this->assertEquals('https://example.com/', $output['items'][0]['properties']['url'][0]);

    $this->assertArrayHasKey('name', $output['items'][0]['properties']);
    $this->assertEquals('Example.com homepage', $output['items'][0]['properties']['name'][0]);
  }

  public function testResolveFromDataElement() {
    $parser = new Parser('
<data class="u-url" value="relative.html"></data>
', 'https://example.com/index.html');
    $output = $parser->parse();

    $this->assertArrayHasKey('url', $output['items'][0]['properties']);
    $this->assertEquals('https://example.com/relative.html', $output['items'][0]['properties']['url'][0]);
  }

}

repo_name: spookie/gnu

license: mit


code:
<?php

/**
 * Tests of the parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2;
use Mf2\Parser;
use PHPUnit_Framework_TestCase;

class ParseValueClassTitleTest extends PHPUnit_Framework_TestCase {

	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	public function testValueClassTitleHandlesSingleValueClass() {
		$input = '

Name (this should not be included)

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Name', $output['items'][0]['properties']['name'][0]);
	}

	public function testValueClassTitleHandlesMultipleValueClass() {
		$input = '

Name (this should not be included) Endname

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('NameEndname', $output['items'][0]['properties']['name'][0]);
	}

	public function testValueClassTitleHandlesSingleValueTitle() {
		$input = '

Wrong Name (this should not be included)

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Real Name', $output['items'][0]['properties']['name'][0]);
	}

	public function testValueClassTitleHandlesMultipleValueTitle() {
		$input = '

Wrong Name (this should not be included)

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Real Name', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/25
	 */
	public function testValueClassDatetimeWorksWithUrlProperties() {
		$input = <<<EOT

			<time class="value">10:17</time>
			on <time class="value">2013-06-27</time>

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('published', $output['items'][0]['properties']);
		$this->assertEquals('2013-06-27 10:17', $output['items'][0]['properties']['published'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/27
	 */
	public function testParsesValueTitleDatetimes() {
		$input = <<<EOT

test

  16.02.2012

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2012-02-16T16:14:47+00:00', $output['items'][0]['properties']['published'][0]);
	}

	/** @see https://github.com/indieweb/php-mf2/issues/34 */
	public function testIgnoresValueClassNestedFurtherThanChild() {
		$test = '
12345678';
		$result = Mf2\parse($test);
		$this->assertEquals('1234', $result['items'][0]['properties']['tel'][0]);
		$this->assertEquals('5678', $result['items'][0]['children'][0]['properties']['tel'][0]);
	}

	/** @see https://github.com/indieweb/php-mf2/issues/38 */
	public function testValueClassDtMatchesSingleDigitTimeComponent() {
		$test = '
<time class="value">6:01</time>, <time class="value">2013-02-01</time>
';
		$result = Mf2\parse($test);
		$this->assertEquals('2013-02-01 6:01', $result['items'][0]['properties']['published'][0]);
	}
}


code:
<?php

namespace Mf2\Parser\Test;

use Mf2\Parser;
use Mf2;
use PHPUnit_Framework_TestCase;

/**
 * Parser Test
 *
 * Contains tests for internal parsing functions and stuff which doesn’t go anywhere else, i.e.
 * isn’t related to a particular property as such.
 *
 * Stuff for parsing E goes in here until there is enough of it to go elsewhere (like, never?)
 */
class ParserTest extends PHPUnit_Framework_TestCase {

	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	public function testUnicodeTrim() {
		$this->assertEquals('thing', Mf2\unicodeTrim('  thing  '));
		$this->assertEquals('thing', Mf2\unicodeTrim('			thing			'));
		$this->assertEquals('thing', Mf2\unicodeTrim(mb_convert_encoding('   thing   ', 'UTF-8', 'HTML-ENTITIES') ));
	}

	public function testMicroformatNameFromClassReturnsFullRootName() {
		$expected = array('h-card');
		$actual = Mf2\mfNamesFromClass('someclass h-card someotherclass', 'h-');

		$this->assertEquals($expected, $actual);
	}

	public function testMicroformatNameFromClassHandlesMultipleHNames() {
		$expected = array('h-card', 'h-person');
		$actual = Mf2\mfNamesFromClass('someclass h-card someotherclass h-person yetanotherclass', 'h-');

		$this->assertEquals($expected, $actual);
	}

	public function testMicroformatStripsPrefixFromPropertyClassname() {
		$expected = array('name');
		$actual = Mf2\mfNamesFromClass('someclass p-name someotherclass', 'p-');

		$this->assertEquals($expected, $actual);
	}

	public function testNestedMicroformatPropertyNameWorks() {
		$expected = array('location' => array('p-'), 'author' => array('u-', 'p-'));
		$test = 'someclass p-location someotherclass u-author p-author';
		$actual = Mf2\nestedMfPropertyNamesFromClass($test);

		$this->assertEquals($expected, $actual);
	}

	public function testMicroformatNamesFromClassIgnoresPrefixesWithoutNames() {
		$expected = array();
		$actual = Mf2\mfNamesFromClass('someclass h- someotherclass', 'h-');

		$this->assertEquals($expected, $actual);
	}

	public function testMicroformatNamesFromClassHandlesExcessiveWhitespace() {
		$expected = array('h-card');
		$actual = Mf2\mfNamesFromClass('  someclass
				h-card 	 someotherclass		   	 ', 'h-');

		$this->assertEquals($expected, $actual);
	}

	public function testMicroformatNamesFromClassIgnoresUppercaseClassnames() {
		$expected = array();
		$actual = Mf2\mfNamesFromClass('H-ENTRY', 'h-');

		$this->assertEquals($expected, $actual);
	}

	public function testParseE() {
		$input = '

Here is a load of embedded markup

';
		//$parser = new Parser($input);
		$output = Mf2\parse($input);

		$this->assertArrayHasKey('content', $output['items'][0]['properties']);
		$this->assertEquals('Here is a load of embedded markup', $output['items'][0]['properties']['content'][0]['html']);
		$this->assertEquals('Here is a load of embedded markup', $output['items'][0]['properties']['content'][0]['value']);
	}

	public function testParseEmptyE() {
		$input = '

Name

';
		//$parser = new Parser($input);
		$output = Mf2\parse($input);

		$this->assertEquals('Name', $output['items'][0]['properties']['name'][0]);
		$this->assertArrayHasKey('content', $output['items'][0]['properties']);
		$this->assertEquals('', $output['items'][0]['properties']['content'][0]['html']);
		$this->assertEquals('', $output['items'][0]['properties']['content'][0]['value']);
	}

	public function testParseEResolvesRelativeLinks() {
		$input = '

Blah blah thing. <object data="/object"></object>

';
		$parser = new Parser($input, 'http://example.com');
		$output = $parser->parse();

		$this->assertEquals('Blah blah thing. <object data="http://example.com/object"></object> ', $output['items'][0]['properties']['content'][0]['html']);
		$this->assertEquals('Blah blah thing. http://example.com/img', $output['items'][0]['properties']['content'][0]['value']);
	}

	public function testParseEWithBR() {
		$input = '

Here is content with two lines.
The br tag should not be converted to an XML br/br element.

';
		//$parser = new Parser($input);
		$output = Mf2\parse($input);

		$this->assertArrayHasKey('content', $output['items'][0]['properties']);
		$this->assertEquals('Here is content with two lines.
The br tag should not be converted to an XML br/br element.', $output['items'][0]['properties']['content'][0]['html']);
		$this->assertEquals('Here is content with two lines.'."\n".'The br tag should not be converted to an XML br/br element.', $output['items'][0]['properties']['content'][0]['value']);
	}

	public function testParseEWithWhitespace() {
		$input = '

		This leading and trailing whitespace should be removed from the HTML and text values.

';
		//$parser = new Parser($input);
		$output = Mf2\parse($input);

		$this->assertArrayHasKey('content', $output['items'][0]['properties']);
		$this->assertEquals('This leading and trailing whitespace should be removed from the HTML and text values.', $output['items'][0]['properties']['content'][0]['html']);
		$this->assertEquals('This leading and trailing whitespace should be removed from the HTML and text values.', $output['items'][0]['properties']['content'][0]['value']);
	}

	/**
	 * @group parseH
	 */
	public function testInvalidClassnamesContainingHAreIgnored() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		// Look through $output for an item which indicate failure
		foreach ($output['items'] as $item) {
			if (in_array('asdfgh-jkl', $item['type']))
				$this->fail();
		}
	}

	public function testHtmlSpecialCharactersWorks() {
		$this->assertEquals('<>', htmlspecialchars('<>'));
	}

	public function testHtmlEncodesNonEProperties() {
		$input = '

			<p>
			<dt>
			<u>

';

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('
', $output['items'][0]['properties']['name'][0]);
		$this->assertEquals('
', $output['items'][0]['properties']['published'][0]);
		$this->assertEquals('', $output['items'][0]['properties']['url'][0]);
	}

	public function testHtmlEncodesImpliedProperties() {
		$input = '<name>';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('<name>', $output['items'][0]['properties']['name'][0]);
		$this->assertEquals('<url>', $output['items'][0]['properties']['url'][0]);
		$this->assertEquals('', $output['items'][0]['properties']['photo'][0]);
	}

	public function testParsesRelValues() {
		$input = 'Mr. Author';
		$parser = new Parser($input);

		$output = $parser->parse();

		$this->assertArrayHasKey('rels', $output);
		$this->assertEquals('http://example.com', $output['rels']['author'][0]);
	}

	public function testParsesRelAlternateValues() {
		$input = 'German Homepage';
		$parser = new Parser($input);
		$parser->enableAlternates = true;
		$output = $parser->parse();

		$this->assertArrayHasKey('alternates', $output);
		$this->assertEquals('http://example.org', $output['alternates'][0]['url']);
		$this->assertEquals('home', $output['alternates'][0]['rel']);
		$this->assertEquals('de', $output['alternates'][0]['hreflang']);
		$this->assertEquals('screen', $output['alternates'][0]['media']);
		$this->assertEquals('text/html', $output['alternates'][0]['type']);
		$this->assertEquals('German Homepage Link', $output['alternates'][0]['title']);
		$this->assertEquals('German Homepage', $output['alternates'][0]['text']);
	}

	public function testParseFromIdOnlyReturnsMicroformatsWithinThatId() {
		$input = <<<EOT

Not Included

	Included

Not Included

EOT;

		$parser = new Parser($input);
		$output = $parser->parseFromId('parse-here');

		$this->assertCount(1, $output['items']);
		$this->assertEquals('Included', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * Issue #21 github.com/indieweb/php-mf2/issues/21
	 */
	public function testDoesntAddArraysWithOnlyValueForAlreadyParsedNestedMicroformats() {
		$input = <<<EOT

		Nested Author

	Real Author

EOT;
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertCount(1, $output['items'][0]['properties']['author']);
	}

	public function testParsesNestedMicroformatsWithClassnamesInAnyOrder() {
		$input = <<<EOT

Name

EOT;
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertCount(1, $output['items'][0]['properties']['in-reply-to']);
		$this->assertEquals('Name', $output['items'][0]['properties']['in-reply-to'][0]['properties']['name'][0]);
	}

	/**
	 * @group internet
	 */
	public function testFetchMicroformats() {
		$mf = Mf2\fetch('http://waterpigs.co.uk/');
		$this->assertArrayHasKey('items', $mf);

		$mf = Mf2\fetch('http://waterpigs.co.uk/photo.jpg', null, $curlInfo);
		$this->assertNull($mf);
		$this->assertContains('jpeg', $curlInfo['content_type']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/48
	 */
	public function testIgnoreClassesEndingInHyphen() {
		$input = ' foo ';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayNotHasKey('0', $output['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/52
	 * @see https://github.com/tommorris/mf2py/commit/92740deb7e19b8f1e7fbf6bec001cf52f2b07e99
	 */
	public function testIgnoresTemplateElements() {
		$result = Mf2\parse('<template class="h-card">Tom Morris</template>');
		$this->assertCount(0, $result['items']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/53
	 * @see http://microformats.org/wiki/microformats2-parsing#parsing_an_e-_property
	 */
	public function testConvertsNestedImgElementToAltOrSrc() {
		$input = <<<EOT

It is a strange thing to see a

EOT;
		$result = Mf2\parse($input, 'http://waterpigs.co.uk/articles/five-legged-elephant');
		$this->assertEquals('It is a strange thing to see a five legged elephant', $result['items'][0]['properties']['content'][0]['value']);
	}

	// parser not respecting not[h-*] in rule  "else if .h-x>a[href]:only-of-type:not[.h-*] then use that [href] for url"
	public function testNotImpliedUrlFromHCard() {
		$input = <<<EOT

	John Q

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayNotHasKey('url', $output['items'][0]['properties']);
	}

	public function testAreaTag() {
		$input = <<<EOT

	<area class="p-category h-card" href="http://personB.example.com" alt="Person Bee" shape="rect" coords="100,100,120,120">

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		// p-name is no longer implied for this test due to nested microformat
		// see https://github.com/microformats/microformats2-parsing/issues/6
		$this->assertArrayNotHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('rect', $output['items'][0]['properties']['category'][0]['shape']);
		$this->assertEquals('100,100,120,120', $output['items'][0]['properties']['category'][0]['coords']);
		$this->assertEquals('Person Bee', $output['items'][0]['properties']['category'][0]['value']);
	}

	public function testParseHcardInCategory() {
		$input = <<<EOT

	Alice tagged
	Bob Smith in

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertContains('h-entry', $output['items'][0]['type']);
		$this->assertArrayHasKey('category', $output['items'][0]['properties']);
		$this->assertContains('h-card', $output['items'][0]['properties']['category'][0]['type']);
		$this->assertArrayHasKey('name', $output['items'][0]['properties']['category'][0]['properties']);
		$this->assertEquals('Bob Smith', $output['items'][0]['properties']['category'][0]['properties']['name'][0]);
		$this->assertArrayHasKey('url', $output['items'][0]['properties']['category'][0]['properties']);
		$this->assertEquals('http://b.example.com/', $output['items'][0]['properties']['category'][0]['properties']['url'][0]);
	}

	public function testApplyTransformationToSrcset() {
		$transformation = function ($url) {
			return 'https://example.com/' . ltrim($url, '/');
		};

		// Example from https://developers.whatwg.org/edits.html#attr-img-srcset
		$srcset = 'banner-HD.jpeg 2x, banner-phone.jpeg 100w, banner-phone-HD.jpeg 100w 2x';
		$result = Mf2\applySrcsetUrlTransformation($srcset, $transformation);
		$this->assertEquals('https://example.com/banner-HD.jpeg 2x, https://example.com/banner-phone.jpeg 100w, https://example.com/banner-phone-HD.jpeg 100w 2x', $result);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/84
	 * @group internet
	 */
	public function testRelativeURLResolvedWithFinalURL() {
		$mf = Mf2\fetch('http://aaron.pk/4Zn5');

		$this->assertEquals('https://aaronparecki.com/2014/12/23/5/photo.jpeg', $mf['items'][0]['properties']['photo'][0]);
	}

	public function testScriptTagContentsRemovedFromTextValue() {
		$input = <<<EOT

		Hello World

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertContains('h-entry', $output['items'][0]['type']);
		$this->assertContains('Hello World', $output['items'][0]['properties']['content'][0]);
		$this->assertNotContains('alert', $output['items'][0]['properties']['content'][0]);
	}

	public function testScriptElementContentsRemovedFromAllPlaintextValues() {
		$input = <<<EOT

	contained
	contained

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertNotContains('not contained', $output['items'][0]['properties']['published'][0]);
		$this->assertNotContains('not contained', $output['items'][0]['properties']['url'][0]);
	}

	public function testScriptTagContentsNotRemovedFromHTMLValue() {
		$input = <<<EOT

		Hello World

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertContains('h-entry', $output['items'][0]['type']);
		$this->assertContains('Hello World', $output['items'][0]['properties']['content'][0]['value']);
		$this->assertContains('Hello World', $output['items'][0]['properties']['content'][0]['html']);
		# The script and style tags should be removed from plaintext results but left in HTML results.
		$this->assertContains('alert', $output['items'][0]['properties']['content'][0]['html']);
		$this->assertNotContains('alert', $output['items'][0]['properties']['content'][0]['value']);
		$this->assertContains('visibility', $output['items'][0]['properties']['content'][0]['html']);
		$this->assertNotContains('visibility', $output['items'][0]['properties']['content'][0]['value']);
	}

	public function testWhitespaceBetweenElements() {
		$input = <<<EOT

	<data class="p-rsvp" value="yes">I'm attending</data>
	Homebrew Website Club at Quip

Thanks for hosting!

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertContains('h-entry', $output['items'][0]['type']);
		// p-name is no longer implied for this test due to other p-*
		// see https://github.com/microformats/microformats2-parsing/issues/6
		$this->assertArrayNotHasKey('name', $output['items'][0]['properties']);
	}

	/**
	 * @see http://www.kevinmarks.com/twitterutils.html
	 */
	public function testCamelCaseClassNames() {
		$input = <<<EOT
<div class="EmbeddedTweet js-clickToOpenTarget" data-click-to-open-target="https://twitter.com/kevinmarks/status/700752598123433985" data-iframe-title="Twitter Tweet" data-dt-full="%{hours12}:%{minutes} %{amPm} - %{day} %{month} %{year}" data-dt-months="Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec" data-dt-am="AM" data-dt-pm="PM" data-dt-now="now" data-dt-s="s" data-dt-m="m" data-dt-h="h" data-dt-second="second" data-dt-seconds="seconds" data-dt-minute="minute" data-dt-minutes="minutes" data-dt-hour="hour" data-dt-hours="hours" data-dt-abbr="%{number}%{symbol}" data-dt-short="%{day} %{month}" data-dt-long="%{day} %{month} %{year}" data-scribe="page:tweet" id="twitter-widget-0" lang="en" data-twitter-event-id="0">

 Follow

		Kevin Marks

		@kevinmarks

I wish people would stop using u- as a prefix for utility classes in CSS. Use util- instead. You're messing with my microformats.

<time class="dt-updated" datetime="2016-02-19T18:43:33+0000" pubdate="" title="Time posted: 19 Feb 2016, 18:43:33 (UTC)">10:43 AM - 19 Feb 2016</time>

    1
		1 Retweet

    4
		4 likes

EOT;

		$output = Mf2\parse($input);

		$this->assertArrayNotHasKey('linkBlend', $output['items'][0]['properties']);
		$this->assertArrayNotHasKey('hiddenInNarrowEnv', $output['items'][0]['properties']);
		$this->assertArrayNotHasKey('floatRight', $output['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/127
	 */
	public function testCamelCaseRootClassNames() {
		$input = '
 content
';
		$output = Mf2\parse($input);

		$this->assertEmpty($output['items']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/127
	 */
	public function testMisTypedRootClassNames() {
		$input = '
"> content

"> content

 content

 content

 content
';
		$output = Mf2\parse($input);

		$this->assertEmpty($output['items']);
	}

	public function testClassNameNumbers() {
		$input = '

Test

';
		$output = Mf2\parse($input);

		$this->assertArrayNotHasKey('column1', $output['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/microformats/microformats2-parsing/issues/6#issuecomment-366473390
	 */
	public function testNoImpliedNameWhenE()
	{
		$input = '

Wanted content.

Footer to be ignored.

';
		$output = Mf2\parse($input);

		$this->assertArrayNotHasKey('name', $output['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/microformats/microformats2-parsing/issues/6#issuecomment-366473390
	 */
	public function testNoImpliedNameWhenP()
	{
		$input = '

Wanted content.

Footer to be ignored.

';
		$output = Mf2\parse($input);

		$this->assertArrayNotHasKey('name', $output['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/microformats/microformats2-parsing/issues/6#issuecomment-366473390
	 */
	public function testNoImpliedNameWhenNestedMicroformat()
	{
		$input = '

I really like Microformats

Footer to be ignored.

';
		$output = Mf2\parse($input);

		$this->assertArrayNotHasKey('name', $output['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/143
	 */
	public function testChildObjects() {
		$input = <<<END

		<title>Test</title>

			Author Name

					One

					Two

					Three

					Four

END;
		$output = Mf2\parse($input);

		$this->assertArrayHasKey('author', $output['items'][0]['properties']);
		$this->assertEquals('Author Name', $output['items'][0]['properties']['author'][0]['properties']['name'][0]);
		$this->assertCount(4, $output['items'][0]['children']);
		$this->assertEquals('One', $output['items'][0]['children'][0]['properties']['name'][0]);
		$this->assertEquals('Two', $output['items'][0]['children'][1]['properties']['name'][0]);
		$this->assertEquals('Three', $output['items'][0]['children'][2]['properties']['name'][0]);
		$this->assertEquals('Four', $output['items'][0]['children'][3]['properties']['name'][0]);
	}

	public function testMultiLevelRecursion() {
		$input = <<<END

		<title>Test</title>

			Author Name

					One

					Two

Comment A

Comment B

					Three

Comment C

Comment D

					Four

END;
		$output = Mf2\parse($input);

		$this->assertArrayHasKey('author', $output['items'][0]['properties']);
		$this->assertEquals('Author Name', $output['items'][0]['properties']['author'][0]['properties']['name'][0]);
		$this->assertCount(4, $output['items'][0]['children']);
		$this->assertEquals('One', $output['items'][0]['children'][0]['properties']['name'][0]);
		$this->assertEquals('Two', $output['items'][0]['children'][1]['properties']['name'][0]);
		$this->assertEquals('Comment A', $output['items'][0]['children'][1]['properties']['comment'][0]['properties']['name'][0]);
		$this->assertEquals('Comment B', $output['items'][0]['children'][1]['properties']['comment'][1]['properties']['name'][0]);
		$three = $output['items'][0]['children'][2];
		$this->assertEquals('Three', $three['properties']['name'][0]);
		$this->assertEquals('Comment C', $three['children'][0]['properties']['name'][0]);
		$this->assertEquals('Comment D', $three['children'][1]['properties']['name'][0]);
		$this->assertEquals('Four', $output['items'][0]['children'][3]['properties']['name'][0]);
	}

	public function testNoErrantWhitespaceOnEHtml()
	{
		$input = '

1

2

';
		$output = Mf2\parse($input);
		$this->assertEquals('
1

2
', $output['items'][0]['properties']['content'][0]['html']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/158
	 */
	public function testPrefixWithNumbers() {
		$input = '

	<data class="p-name" value="Coffee"></data>

		Coffee

';
		$output = Mf2\parse($input);

		$this->assertArrayHasKey('p3k-drank', $output['items'][0]['properties']);
		$this->assertCount(1, $output['items'][0]['properties']['p3k-drank']);
		$this->assertEquals('h-p3k-food', $output['items'][0]['properties']['p3k-drank'][0]['type'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/160
	 */
	public function testConsecutiveDashes() {
		$input = '

 http://example.com/post posted:

Too many dashes
leading dash
middle dash
trailing dash

';
		$output = Mf2\parse($input);

		$this->assertCount(1, $output['items'][0]['type']);
		$this->assertEquals('h-entry', $output['items'][0]['type'][0]);
		$this->assertCount(1, $output['items'][0]['properties']);
		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
	}

	/**
	 * Additional test from mf2py. Covers consecutive dashes, numbers in vendor prefix, and capital letters.
	 * Added markup for numbers-only prefix and capital letter in prefix
	 * @see https://github.com/kartikprabhu/mf2py/blob/experimental/test/examples/class_names_format.html
	 * @see https://github.com/indieweb/php-mf2/issues/160
	 * @see https://github.com/indieweb/php-mf2/issues/158
	 */
	public function testMfClassRegex() {
		$input = '

		URL
		name

';
		$output = Mf2\parse($input);

		$this->assertCount(3, $output['items'][0]['type']);
		$this->assertContains('h-feed', $output['items'][0]['type']);
		$this->assertContains('h-p3k-entry', $output['items'][0]['type']);
		$this->assertContains('h-x-test', $output['items'][0]['type']);
		$this->assertCount(5, $output['items'][0]['properties']);
		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertArrayHasKey('p3k-url', $output['items'][0]['properties']);
		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertArrayHasKey('p3k-name', $output['items'][0]['properties']);
		$this->assertArrayHasKey('123-url', $output['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/microformats/microformats2-parsing/issues/30
	 */
	public function testUniqueAndAlphabeticalMfClasses() {
		$input = '

';
		$output = Mf2\parse($input);

		$this->assertEquals(array('h-cite', 'h-entry'), $output['items'][0]['type']);
	}

	/**
	 * The default DOMDocument parser will trip here because it does not know HTML5 elements.
	 * @see https://html.spec.whatwg.org/#optional-tags:the-p-element
	 **/
	public function testHtml5OptionalPEndTag() {
		if (!class_exists('Masterminds\\HTML5')) {
			$this->markTestSkipped('masterminds/html5 is required for this test.');
		}
		$input = '

Name
Not Name

';
		$output = Mf2\parse($input);

		$this->assertEquals('Name', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * Make sure the parser does not mutate any DOMDocument instances passed to the constructor.
	 * @see https://github.com/indieweb/php-mf2/issues/174
	 * @see https://github.com/microformats/mf2py/issues/104
	 */
	public function testNotMutatingPassedInDOM() {
		$input = file_get_contents(__DIR__ . '/snarfed.org.html');

		// Use same parsing as Parser::__construct(), twice to have a comparison object.
		libxml_use_internal_errors(true);
		$refDoc = new \DOMDocument();
		@$refDoc->loadHTML(Mf2\unicodeToHtmlEntities($input));
		$inputDoc = new \DOMDocument();
		@$inputDoc->loadHTML(Mf2\unicodeToHtmlEntities($input));

		// For completion sake, test PHP itself.
		$this->assertEquals($refDoc, $inputDoc, 'PHP could not create identical DOMDocument instances.');

		// Parse one DOMDocument instance, and test if it is still the same as the other.
		Mf2\parse($inputDoc, 'http://snarfed.org/2013-10-23_oauth-dropins');
		$this->assertEquals($refDoc, $inputDoc, 'Parsing mutated the DOMDocument.');
	}

	public function testNoImpliedURLForEmptyProperties() {
		// In the 0.4.5 release, this caused an error
		// https://github.com/microformats/php-mf2/issues/196

		$input = <<<EOD

EOD;

		$output = Mf2\parse($input);
		$this->assertInternalType('array', $output['items'][0]['properties']['comment'][0]['properties']);
		$this->assertInternalType('array', $output['items'][0]['properties']['comment'][0]['children'][0]['properties']);
		$this->assertEmpty($output['items'][0]['properties']['comment'][0]['properties']);
		$this->assertEmpty($output['items'][0]['properties']['comment'][0]['children'][0]['properties']);
  }

  /**
	 * Make sure day of year passed to normalizeOrdinalDate() is valid
	 * @see https://github.com/indieweb/php-mf2/issues/167
	 */
	public function testInvalidOrdinalDate() {
		# 365 days in non-leap years
		$this->assertEquals('2018-12-31', Mf2\normalizeOrdinalDate('2018-365'));
		$this->assertEquals('', Mf2\normalizeOrdinalDate('2018-366'));
		# 366 days in leap years
		$this->assertEquals('2016-12-31', Mf2\normalizeOrdinalDate('2016-366'));
		$this->assertEquals('', Mf2\normalizeOrdinalDate('2016-367'));
	}
}


code:
<?php

namespace Mf2\Parser\Test;

class PlainTextTest extends \PHPUnit_Framework_TestCase {
    /**
     * @dataProvider aaronpkExpectations
     */
    public function testAaronpkExpectations($input, $pName, $eValue, $eHtml) {
        $parser = new \Mf2\Parser($input);
        $output = $parser->parse();
        $entryProperties = $output['items'][0]['properties'];
        $this->assertEquals($pName, $entryProperties['name'][0]);
        $this->assertEquals($eValue, $entryProperties['content'][0]['value']);
        $this->assertEquals($eHtml, $entryProperties['content'][0]['html']);
    }

    public function aaronpkExpectations() {
        return array(
            1 => array(
                "
\n

Hello World

\n
",
                "Hello World",
                "Hello World",
                "
Hello World
"
            ),
            2 => array(
                "
\n

Hello
World

\n
",
                "Hello\nWorld",
                "Hello\nWorld",
                "
Hello
World
"
            ),
            3 => array(
                "
\n

Hello
\nWorld

\n
",
                "Hello\nWorld",
                "Hello\nWorld",
                "
Hello
\nWorld
"
            ),
            4 => array(
                "
\n
\n
Hello World
\n
\n
",
                "Hello World",
                "Hello World",
                "
Hello World
"
            ),
            5 => array(
                "
\n
Hello\nWorld
\n
",
                "Hello World",
                "Hello World",
                "Hello\nWorld"
            ),
            6 => array(
                "
\n

Hello

World

\n
",
                "Hello\nWorld",
                "Hello\nWorld",
                "
Hello

World
"
            ),
            7 => array(
                "
\n
Hello
\n    World
\n
",
                "Hello\nWorld",
                "Hello\nWorld",
                "Hello
\n    World",
            ),
            8 => array(
                "
\n

Hello
World

\n
",
                "Hello\nWorld",
                "Hello\nWorld",
                "
Hello
World
"
            ),
            9 => array(
                "
\n
\n
One
\n
Two
\n
Three
\n
\n
",
                "One\nTwo\nThree",
                "One\nTwo\nThree",
                "
One
\n
Two
\n
Three
"
            )
        );
    }
}


code:
<?php
/**
 * Tests of the parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2;
use Mf2\Parser;
use PHPUnit_Framework_TestCase;

class RelTest extends PHPUnit_Framework_TestCase {
  public function setUp() {
    date_default_timezone_set('Europe/London');
  }

  public function testRelValueOnLinkTag() {
    $input = '<link rel="webmention" href="http://example.com/webmention">';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('webmention', $output['rels']);
    $this->assertEquals('http://example.com/webmention', $output['rels']['webmention'][0]);
  }

  public function testRelValueOnATag() {
    $input = 'webmention me';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('webmention', $output['rels']);
    $this->assertEquals('http://example.com/webmention', $output['rels']['webmention'][0]);
  }

  public function testRelValueOnAreaTag() {
    $input = '<map><area rel="webmention" href="http://example.com/webmention"/></map>';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('webmention', $output['rels']);
    $this->assertEquals('http://example.com/webmention', $output['rels']['webmention'][0]);
  }

  public function testRelValueOrder() {
    $input = '<map><area rel="webmention" href="http://example.com/area"/></map>
      webmention me
      <link rel="webmention" href="http://example.com/link">';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('webmention', $output['rels']);
    $this->assertEquals('http://example.com/area', $output['rels']['webmention'][0]);
    $this->assertEquals('http://example.com/a', $output['rels']['webmention'][1]);
    $this->assertEquals('http://example.com/link', $output['rels']['webmention'][2]);
  }

  public function testRelValueOrder2() {
    $input = '<map><area rel="webmention" href="http://example.com/area"/></map>
      <link rel="webmention" href="http://example.com/link">
      webmention me';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('webmention', $output['rels']);
    $this->assertEquals('http://example.com/area', $output['rels']['webmention'][0]);
    $this->assertEquals('http://example.com/link', $output['rels']['webmention'][1]);
    $this->assertEquals('http://example.com/a', $output['rels']['webmention'][2]);
  }

  public function testRelValueOrder3() {
    $input = '

        <link rel="webmention" href="http://example.com/link">

        webmention me
        <map><area rel="webmention" href="http://example.com/area"/></map>

    ';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('webmention', $output['rels']);
    $this->assertEquals('http://example.com/link', $output['rels']['webmention'][0]);
    $this->assertEquals('http://example.com/a', $output['rels']['webmention'][1]);
    $this->assertEquals('http://example.com/area', $output['rels']['webmention'][2]);
  }

  public function testRelValueOnBTag() {
    $input = 'this makes no sense';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayNotHasKey('webmention', $output['rels']);
  }

  public function testEnableAlternatesFlagTrue() {
    $input = 'author a
author b
post 1
post 2
French mobile homepage';
    $parser = new Parser($input);
    $parser->enableAlternates = true;
    $output = $parser->parse();

    $this->assertArrayHasKey('alternates', $output);
  }

  public function testEnableAlternatesFlagFalse() {
    $input = 'author a
author b
post 1
post 2
French mobile homepage';
    $parser = new Parser($input);
    $parser->enableAlternates = false;
    $output = $parser->parse();

    $this->assertArrayNotHasKey('alternates', $output);
  }

  /**
   * @see https://github.com/indieweb/php-mf2/issues/112
   * @see http://microformats.org/wiki/microformats2-parsing#rel_parse_examples
   */
  public function testRelURLs() {
    $input = 'author a
author b
post 1
post 2
French mobile homepage
<link rel="alternate" type="application/atom+xml" href="http://example.com/articles.atom" title="Atom Feed" />';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('rels', $output);
    $this->assertCount(4, $output['rels']);
    $this->assertArrayHasKey('author', $output['rels']);
    $this->assertArrayHasKey('in-reply-to', $output['rels']);
    $this->assertArrayHasKey('alternate', $output['rels']);
    $this->assertArrayHasKey('home', $output['rels']);

    $this->assertArrayHasKey('rel-urls', $output);
    $this->assertCount(6, $output['rel-urls']);
    $this->assertArrayHasKey('http://example.com/a', $output['rel-urls']);
    $this->assertArrayHasKey('http://example.com/b', $output['rel-urls']);
    $this->assertArrayHasKey('http://example.com/1', $output['rel-urls']);
    $this->assertArrayHasKey('http://example.com/2', $output['rel-urls']);
    $this->assertArrayHasKey('http://example.com/fr', $output['rel-urls']);
    $this->assertArrayHasKey('http://example.com/articles.atom', $output['rel-urls']);

    $this->assertArrayHasKey('rels', $output['rel-urls']['http://example.com/a']);
    $this->assertArrayHasKey('text', $output['rel-urls']['http://example.com/a']);
    $this->assertArrayHasKey('rels', $output['rel-urls']['http://example.com/b']);
    $this->assertArrayHasKey('text', $output['rel-urls']['http://example.com/b']);
    $this->assertArrayHasKey('rels', $output['rel-urls']['http://example.com/1']);
    $this->assertArrayHasKey('text', $output['rel-urls']['http://example.com/1']);
    $this->assertArrayHasKey('rels', $output['rel-urls']['http://example.com/2']);
    $this->assertArrayHasKey('text', $output['rel-urls']['http://example.com/2']);
    $this->assertArrayHasKey('rels', $output['rel-urls']['http://example.com/fr']);
    $this->assertArrayHasKey('text', $output['rel-urls']['http://example.com/fr']);
    $this->assertArrayHasKey('media', $output['rel-urls']['http://example.com/fr']);
    $this->assertArrayHasKey('hreflang', $output['rel-urls']['http://example.com/fr']);
    $this->assertArrayHasKey('title', $output['rel-urls']['http://example.com/articles.atom']);
    $this->assertArrayHasKey('type', $output['rel-urls']['http://example.com/articles.atom']);
    $this->assertArrayHasKey('rels', $output['rel-urls']['http://example.com/articles.atom']);
  }

  /**
   * @see https://github.com/microformats/microformats2-parsing/issues/29
   * @see https://github.com/microformats/microformats2-parsing/issues/30
   */
  public function testRelURLsRelsUniqueAndSorted() {
    $input = '
';
    $parser = new Parser($input);
    $output = $parser->parse();
    $this->assertEquals($output['rel-urls']['#']['rels'], array('archived', 'bookmark', 'me'));
  }

  public function testRelURLsInfoMergesCorrectly() {
    $input = 'This nodeValue
Not this nodeValue';
    $parser = new Parser($input);
    $output = $parser->parse();
    $this->assertEquals($output['rel-urls']['#']['hreflang'], 'en');
    $this->assertArrayNotHasKey('media', $output['rel-urls']['#']);
    $this->assertArrayNotHasKey('title', $output['rel-urls']['#']);
    $this->assertArrayNotHasKey('type', $output['rel-urls']['#']);
    $this->assertEquals($output['rel-urls']['#']['text'], 'This nodeValue');
  }

  public function testRelURLsNoDuplicates() {
    $input = '

';
    $parser = new Parser($input);
    $output = $parser->parse();
    $this->assertEquals($output['rels']['a'], array('#a', '#b'));
  }

  public function testRelURLsFalsyTextVSEmpty() {
    $input = '0
';
    $parser = new Parser($input);
    $output = $parser->parse();
    $this->assertArrayHasKey('text', $output['rel-urls']['#a']);
    $this->assertEquals($output['rel-urls']['#a']['text'], '0');
    $this->assertArrayNotHasKey('text', $output['rel-urls']['#b']);
  }

}


code:
<?php

/**
 * Tests of the URL resolver within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2;
use PHPUnit_Framework_TestCase;

class UrlTest extends PHPUnit_Framework_TestCase {

	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	public function testRemoveLeadingDotSlash() {
		$input = '../one/two';
		mf2\removeLeadingDotSlash($input);
		$this->assertEquals('one/two', $input);

		$input = './one/two';
		mf2\removeLeadingDotSlash($input);
		$this->assertEquals('one/two', $input);
	}

	public function testRemoveLeadingSlashDot() {
		$input = '/./one/two';
		mf2\removeLeadingSlashDot($input);
		$this->assertEquals('/one/two', $input);

		$input = '/.';
		mf2\removeLeadingSlashDot($input);
		$this->assertEquals('/', $input);

		$input = '/./../';
		mf2\removeLeadingSlashDot($input);
		$this->assertEquals('/../', $input);

		$input = '/./../../g';
		mf2\removeLeadingSlashDot($input);
		$this->assertEquals('/../../g', $input);
	}

	public function testRemoveOneDirLevel() {
		$input = '/../../g';
		$output = '/a/b/c';
		mf2\removeOneDirLevel($input, $output);
		$this->assertEquals('/../g', $input);
		$this->assertEquals('/a/b', $output);

		$input = '/..';
		$output = '/a/b/c';
		mf2\removeOneDirLevel($input, $output);
		$this->assertEquals('/', $input);
		$this->assertEquals('/a/b', $output);
	}

	public function testRemoveLoneDotDot() {
		$input = '.';
		mf2\removeLoneDotDot($input);
		$this->assertEquals('', $input);

		$input = '..';
		mf2\removeLoneDotDot($input);
		$this->assertEquals('', $input);
	}

	public function testMoveOneSegmentFromInput() {
		$input = '/a/b/c/./../../g';
		$output = '';
		mf2\moveOneSegmentFromInput($input, $output);
		$this->assertEquals('/b/c/./../../g', $input);
		$this->assertEquals('/a', $output);

		$input = '/b/c/./../../g';
		$output = '/a';
		mf2\moveOneSegmentFromInput($input, $output);
		$this->assertEquals('/c/./../../g', $input);
		$this->assertEquals('/a/b', $output);

		$input = '/c/./../../g';
		$output = '/a/b';
		mf2\moveOneSegmentFromInput($input, $output);
		$this->assertEquals('/./../../g', $input);
		$this->assertEquals('/a/b/c', $output);

		$input = '/g';
		$output = '/a';
		mf2\moveOneSegmentFromInput($input, $output);
		$this->assertEquals('', $input);
		$this->assertEquals('/a/g', $output);
	}

	/**
	 * @dataProvider removeDotSegmentsData
	 */
	public function testRemoveDotSegments($assert, $path, $expected) {
		$actual = mf2\removeDotSegments($path);
		$this->assertEquals($expected, $actual, $assert);
	}

	public function removeDotSegmentsData() {
		return array(
			array('Should remove .. and .',
				'/a/b/c/./../../g', '/a/g'),
			array('Should remove ../..',
				'/a/b/c/d/../../../g', '/a/g'),
			array('Should not add leading slash',
				'a/b/c', 'a/b/c'),

		);
	}

	public function testNoPathOnBase() {
		$actual = mf2\resolveUrl('http://example.com', '');
		$this->assertEquals('http://example.com/', $actual);

		$actual = mf2\resolveUrl('http://example.com', '#');
		$this->assertEquals('http://example.com/#', $actual);

		$actual = mf2\resolveUrl('http://example.com', '#thing');
		$this->assertEquals('http://example.com/#thing', $actual);
	}

	public function testMisc() {
		$expected = 'http://a/b/c/g';
		$actual = mf2\resolveUrl('http://a/b/c/d;p?q', './g');
		$this->assertEquals($expected, $actual);

		$expected = 'http://a/b/c/g/';
		$actual = mf2\resolveUrl('http://a/b/c/d;p?q', './g/');
		$this->assertEquals($expected, $actual);

		$expected = 'http://a/b/';
		$actual = mf2\resolveUrl('http://a/b/c/d;p?q', '..');
		$this->assertEquals($expected, $actual);
	}

	/** as per https://github.com/indieweb/php-mf2/issues/35 */
	public function testResolvesProtocolRelativeUrlsCorrectly() {
		$expected = 'http://cdn.example.org/thing/asset.css';
		$actual = Mf2\resolveUrl('http://example.com', '//cdn.example.org/thing/asset.css');
		$this->assertEquals($expected, $actual);

		$expected = 'https://cdn.example.org/thing/asset.css';
		$actual = Mf2\resolveUrl('https://example.com', '//cdn.example.org/thing/asset.css');
		$this->assertEquals($expected, $actual);
	}

	/**
	 * @dataProvider testData
	 */
  public function testReturnsUrlIfAbsolute($assert, $base, $url, $expected) {
    $actual = mf2\resolveUrl($base, $url);

    $this->assertEquals($expected, $actual, $assert);
  }

	public function testData() {
		// seriously, please update to PHP 5.4 so I can use nice array syntax ;)
		// fail message, base, url, expected
		$cases = array(
			array('Should return absolute URL unchanged',
				'http://example.com', 'http://example.com', 'http://example.com'),

			array('Should return root given blank path',
				'http://example.com', '', 'http://example.com/'),

			array('Should return input unchanged given full URL and blank path',
				'http://example.com/something', '', 'http://example.com/something'),

			array('Should handle blank base URL',
				'', 'http://example.com', 'http://example.com'),

			array('Should resolve fragment ID',
				'http://example.com', '#thing', 'http://example.com/#thing'),

			array('Should resolve blank fragment ID',
				'http://example.com', '#', 'http://example.com/#'),

			array('Should resolve same level URL',
				'http://example.com', 'thing', 'http://example.com/thing'),

			array('Should resolve directory level URL',
				'http://example.com', './thing', 'http://example.com/thing'),

			array('Should resolve parent level URL at root level',
				'http://example.com', '../thing', 'http://example.com/thing'),

			array('Should resolve nested URL',
				'http://example.com/something', 'another', 'http://example.com/another'),

			array('Should ignore query strings in base url',
				'http://example.com/index.php?url=http://example.org', '/thing', 'http://example.com/thing'),

			array('Should resolve query strings',
				'http://example.com/thing', '?stuff=yes', 'http://example.com/thing?stuff=yes'),

			array('Should resolve dir level query strings',
				'http://example.com', './?thing=yes', 'http://example.com/?thing=yes'),

			array('Should resolve up one level from root domain',
				'http://example.com', 'path/to/the/../file', 'http://example.com/path/to/file'),

			array('Should resolve up one level from base with path',
				'http://example.com/path/the', 'to/the/../file', 'http://example.com/path/to/file'),

			// Tests from webignition library

			array('relative add host from base',
				'http://www.example.com', 'server.php', 'http://www.example.com/server.php'),

			array('relative add scheme host pass from base',
				'http://:pass@www.example.com', 'server.php', 'http://:pass@www.example.com/server.php'),

			array('relative add scheme host user pass from base',
				'http://user:pass@www.example.com', 'server.php', 'http://user:pass@www.example.com/server.php'),

			array('relative base has file path',
				'http://example.com/index.html', 'example.html', 'http://example.com/example.html'),

			array('input has absolute path',
				'http://www.example.com/pathOne/pathTwo/pathThree', '/server.php?param1=value1', 'http://www.example.com/server.php?param1=value1'),

			array('test absolute url with path',
				'http://www.example.com/', 'http://www.example.com/pathOne', 'http://www.example.com/pathOne'),

			array('testRelativePathIsTransformedIntoCorrectAbsoluteUrl',
				'http://www.example.com/pathOne/pathTwo/pathThree', 'server.php?param1=value1', 'http://www.example.com/pathOne/pathTwo/server.php?param1=value1'),

			array('testAbsolutePathHasDotDotDirecoryAndSourceHasFileName',
				'http://www.example.com/pathOne/index.php', '../jquery.js', 'http://www.example.com/jquery.js'),

			array('testAbsolutePathHasDotDotDirecoryAndSourceHasDirectoryWithTrailingSlash',
				'http://www.example.com/pathOne/', '../jquery.js', 'http://www.example.com/jquery.js'),

			array('testAbsolutePathHasDotDotDirecoryAndSourceHasDirectoryWithoutTrailingSlash',
				'http://www.example.com/pathOne', '../jquery.js', 'http://www.example.com/jquery.js'),

			array('testAbsolutePathHasDotDirecoryAndSourceHasFilename',
				'http://www.example.com/pathOne/index.php', './jquery.js', 'http://www.example.com/pathOne/jquery.js'),

			array('testAbsolutePathHasDotDirecoryAndSourceHasDirectoryWithTrailingSlash',
				'http://www.example.com/pathOne/', './jquery.js', 'http://www.example.com/pathOne/jquery.js'),

			array('testAbsolutePathHasDotDirecoryAndSourceHasDirectoryWithoutTrailingSlash',
				'http://www.example.com/pathOne', './jquery.js', 'http://www.example.com/jquery.js'),

			array('testAbsolutePathIncludesPortNumber',
				'http://example.com:8080/index.html', '/photo.jpg', 'http://example.com:8080/photo.jpg')

		);

		// PHP 5.4 and before returns a different result, but either are acceptable
		if(PHP_MAJOR_VERSION <= 5 && PHP_MINOR_VERSION <= 4) {
			$cases[] = array('relative add scheme host user from base',
				'http://user:@www.example.com', 'server.php', 'http://user@www.example.com/server.php');
		} else {
			$cases[] = array('relative add scheme host user from base',
				'http://user:@www.example.com', 'server.php', 'http://user:@www.example.com/server.php');
		}

		// Test cases from RFC
		// http://tools.ietf.org/html/rfc3986#section-5.4

		$rfcTests = array(
			array("g:h", "g:h"),
			array("g", "http://a/b/c/g"),
			array("./g", "http://a/b/c/g"),
			array("g/", "http://a/b/c/g/"),
			array("/g", "http://a/g"),
			array("//g", "http://g"),
			array("?y", "http://a/b/c/d;p?y"),
			array("g?y", "http://a/b/c/g?y"),
			array("#s", "http://a/b/c/d;p?q#s"),
			array("g#s", "http://a/b/c/g#s"),
			array("g?y#s", "http://a/b/c/g?y#s"),
			array(";x", "http://a/b/c/;x"),
			array("g;x", "http://a/b/c/g;x"),
			array("g;x?y#s", "http://a/b/c/g;x?y#s"),
			array("", "http://a/b/c/d;p?q"),
			array(".", "http://a/b/c/"),
			array("./", "http://a/b/c/"),
			array("..", "http://a/b/"),
			array("../", "http://a/b/"),
			array("../g", "http://a/b/g"),
			array("../..", "http://a/"),
			array("../../", "http://a/"),
			array("../../g", "http://a/g")
		);

		foreach($rfcTests as $i=>$test) {
			$cases[] = array(
				'test rfc ' . $i, 'http://a/b/c/d;p?q', $test[0], $test[1]
			);
		}

		return $cases;
	}
}


code:
<?php

require dirname(__DIR__) . '/../vendor/autoload.php';


code:
<!DOCTYPE html>

<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>oauth-dropins | snarfed.org</title>
<link rel="profile" href="http://gmpg.org/xfn/11" />
<link rel="pingback" href="http://snarfed.org/w/xmlrpc.php" />

<link rel="alternate" type="application/rss+xml" title="snarfed.org » Feed" href="http://snarfed.org/feed" />
<link rel="alternate" type="application/rss+xml" title="snarfed.org » Comments Feed" href="http://snarfed.org/comments/feed" />
<link rel="alternate" type="application/rss+xml" title="snarfed.org » oauth-dropins Comments Feed" href="http://snarfed.org/2013-10-23_oauth-dropins/feed" />
<link rel='stylesheet' id='nextgen_gallery_related_images-css'  href='http://snarfed.org/w/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/nextgen_gallery_display/static/nextgen_gallery_related_images.css?ver=3.7' type='text/css' media='all' />
<link rel='stylesheet' id='jetpack-widgets-css'  href='http://snarfed.org/w/wp-content/plugins/jetpack/modules/widgets/widgets.css?ver=20121003' type='text/css' media='all' />
<link rel='stylesheet' id='ryu-style-css'  href='http://snarfed.org/w/wp-content/themes/snarfed-ryu/style.css?ver=3.7' type='text/css' media='all' />
<link rel='stylesheet' id='ryu-lato-css'  href='http://fonts.googleapis.com/css?family=Lato:100,300,400,700,900,100italic,300italic,400italic,700italic,900italic' type='text/css' media='all' />
<link rel='stylesheet' id='ryu-playfair-display-css'  href='http://fonts.googleapis.com/css?family=Playfair+Display:400,700,900,400italic,700italic,900italic&subset=latin,latin-ext' type='text/css' media='all' />

<link rel='prev' title='RSVP: #Indieweb catchup' href='http://snarfed.org/2013-10-22_rsvp-indieweb-catchup' />

<link rel='canonical' href='http://snarfed.org/2013-10-23_oauth-dropins' />
<link rel='shortlink' href='http://wp.me/p3EDAq-1XE' />
<link rel="openid2.provider" href="https://www.google.com/accounts/o8/ud?source=profiles">
<link rel="openid2.local_id" href="http://www.google.com/profiles/heaven">
<link href="https://plus.google.com/103651231634018158746" rel="publisher" />
<meta property="fb:admins" content="212038" />

<link rel="http://webmention.org/" href="http://snarfed.org/w/?webmention=endpoint" />

<meta property="og:type" content="article" />
<meta property="og:title" content="oauth-dropins" />
<meta property="og:url" content="http://snarfed.org/2013-10-23_oauth-dropins" />
<meta property="og:description" content="Need to use an [OAuth](http://oauth.net/)-protected API in a Python webapp? [oauth-dropins](https://github.com/snarfed/oauth-dropins) is for you! It's a collection of drop-in OAuth client flows for..." />
<meta property="og:site_name" content="snarfed.org" />
<meta property="og:image" content="/oauth_shiny.png" />
<meta name="twitter:site" content="@snarfed_org" />
<meta name="twitter:image" content="/oauth_shiny.png" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:description" content="Need to use an [OAuth](http://oauth.net/)-protected API in a Python webapp? [oauth-dropins](https://github.com/snarfed/oauth-dropins) is for you! It's a collection of drop-in OAuth client flows for..." />

			<link rel="stylesheet" id="custom-css-css" type="text/css" href="http://snarfed.org/?custom-css=1&csblog=1&cscache=6&csrev=45" />

I'm Ryan Barrett.

I live, work, and play in San Francisco.

I code, write, and post pictures here.

      Home

      Search

      Archives

      Twitter

      Facebook

      Google+

      GitHub

      RSS Feed

<form method="get" id="searchform" class="searchform" action="http://snarfed.org/" role="search">
	Search
	<input type="search" class="field" name="s" value="" id="s" placeholder="Search …" />
	<input type="submit" class="submit" id="searchsubmit" value="Search" />
</form>

					Widgets

					Search

			<hgroup>

snarfed.org

Ryan Barrett's blog

			</hgroup>

			Uncategorized
oauth-dropins

			<time class="dt-published" datetime="2013-10-23T10:32:06+00:00">10/23/2013</time> Ryan Barrett
						1 Comment

Need to use an OAuth-protected API in a Python webapp?
oauth-dropins is for you! It’s a
collection of drop-in OAuth client flows for many popular sites. It supports
Facebook, Twitter, Google+, Instagram, Dropbox, Blogger, Tumblr, and
WordPress.com, with more on the way. It also currently requires
Google App Engine, but should support other
platforms in the future.

Try the demo!

You can use oauth-dropins in your project with just a bit of code. For example,
to use it for Facebook, just add these two lines to your WSGI application:

from oauth_dropins import facebook

application = webapp2.WSGIApplication([
  ...
  ('/facebook/start_oauth', facebook.StartHandler.to('/facebook/oauth_callback')),
  ('/facebook/oauth_callback', facebook.CallbackHandler.to('/next')),
  ]

Then map those URLs in your
app.yaml
and put your Facebook app‘s key and
secret in facebook_app_id and facebook_app_secret files in your app’s root
directory, and you’re good to go!

See the GitHub repo for more
details. Happy hacking!

		Standard

				One thought on “oauth-dropins”

					Ryan Barrett says:

Need to use an OAuth-ed API in a Python webapp? oauth-dropins is for you! http://t.co/DHqkNf0OBX Try the demo: http://t.co/8Cg0GFAdDb via Twitter

				<time datetime="2013-10-23T11:20:24+00:00">
				10/23/2013 at 11:20am				</time>

Leave a Reply Cancel reply

									<form action="http://snarfed.org/w/wp-comments-post.php" method="post" id="commentform" class="comment-form">

Your email address will not be published.

Name <input id="author" name="author" type="text" value="" size="30" />

Email <input id="email" name="email" type="text" value="" size="30" />

Website <input id="url" name="url" type="text" value="" size="30" />

Comment <textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea>

You may use these HTML tags and attributes:  <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

							<input name="submit" type="submit" id="submit" value="Post Comment" />
							<input type='hidden' name='comment_post_ID' value='7542' id='comment_post_ID' />
<input type='hidden' name='comment_parent' id='comment_parent' value='0' />

<input type="hidden" id="akismet_comment_nonce" name="akismet_comment_nonce" value="9e21df4fc3" />
					</form>

						Proudly powered by WordPress
			 |
			Theme: Ryu by Automattic.


code: 665 3rd St. Suite 207 San Francisco, CA 94107 U.S.A.


Just a name

description: adr

author: Glenn Jones


code:
    665 3rd St.
    Suite 207
    San Francisco,
    CA
    94107
    U.S.A.


Broken into properties

description: h-adr


adr parsing tests

description: This page was design to test the parsing of adr and its output to the newer JSON structure of micorformats 2. These tests are part of the micorformats 2 test suite.


The <abbr> tag pattern

description: geo


Hidden value-title pattern

description: geo


code:
On my way to The Bricklayer's Arms
    (Geo: 51.513458;-0.14812)


Just a name

description: geo


code:
We are meeting at

    The Bricklayer's Arms
    (Geo: 51.513458:
    -0.14812)


Broken into properties

description: geo


geo parsing tests

description: This page was design to test the parsing of geo and its output to the newer JSON structure of micorformats 2. These tests are part of the micorformats 2 test suite.


Value-title class pattern

description: geo


code:
    Bricklayer's Arms

        3 Charlotte Road,
        City of London,
        EC2A 3PE,
        UK
     –
    Geo:(51.526421;-0.081067)


label: 3 Charlotte Road, City of London, EC2A 3PE, UK


With geo data

description: h-adr


With geo url

description: h-adr


name: 665 3rd St. Suite 207 San Francisco, CA 94107 U.S.A.


Just a name

description: h-adr


Broken into properties

description: h-adr


h-adr parsing tests

description: This page was design to test the parsing of h-adr. These tests are part of the micorformats 2 test suite.


Single child implied pattern

description: h-card


code:
    Mitchell Baker
    (@MitchellBaker)
    Mozilla Foundation

Mitchell is responsible for setting the direction and scope of the Mozilla Foundation and its activities.

Strategy and Leadership


note: Mitchell is responsible for setting the direction and scope of the Mozilla Foundation and its activities.

category: Strategy Leadership


An extended description

description: h-card


code:
  Mitchell Baker
  (Mozilla Foundation)


Organization marked-up with h-card

description: h-card


value: Mozilla Foundation

type: h-card h-org


name: Organization marked-up with h-card and h-org

description: h-card


A hyperlinked photo

description: h-card


Just a hyperlink

description: h-card


Just a name

description: h-card


Additional nested microformats

description: h-card


code:
        John
        P
        Doe

    <data class="p-honorific-suffix" value="MSc"></data>

BSc

BA

    <map name="logomap">
        <area class="p-org" shape="rect" coords="0,0,82,126" href="madgex.htm" alt="Madgex" />
        <area class="p-org" shape="circle" coords="90,58,3" href="mozilla.htm" alt="Mozilla" />
    </map>


p-property

description: h-card


h-card parsing tests

description: This page was design to test the parsing of h-card. These tests are part of the micorformats 2 test suite.


Just a hyperlink

description: h-entry


Just a name

description: h-entry


h-entry parsing tests

description: This page was design to test the parsing of h-entry. These tests are part of the micorformats 2 test suite.


code:
microformats.org at 7

Last week the microformats.org community
            celebrated its 7th birthday at a gathering hosted by Mozilla in
            San Francisco and recognized accomplishments, challenges, and
            opportunities.

The microformats tagline “humans first, machines second”
            forms the basis of many of our
            principles, and
            in that regard, we’d like to recognize a few people and
            thank them for their years of volunteer service

Updated
        <time class="dt-updated" datetime="2012-06-25T17:08:26">June 25th, 2012</time> by
        Tantek


value: Last week the microformats.org community celebrated its 7th birthday at a gathering hosted by Mozilla in San Francisco and recognized accomplishments, challenges, and opportunities. The microformats tagline “humans first, machines second” forms the basis of many of our principles, and in that regard, we’d like to recognize a few people and thank them for their years of volunteer service

value: Tantek


Entry with summary and content

description: h-entry


code:
microformats.org at 7

      Article permalink

        http://microformats.org/ -
        2012/06/25/microformats-org-at-7

Article permalink

    <map name="logomap">
        <area class="u-url" shape="rect" coords="0,0,82,126" href="http://microformats.org/" alt="microformats.org" />
    </map>

    <object class="u-url" data="http://microformats.org/wiki/microformats2-parsing"></object>

    value-class-pattern
    <data class="u-url" value="http://microformats.org/wiki/"></data>

http://microformats.org/discuss


u-property

description: h-entry


code:
    The 4th Microformat party will be on

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07:00:00pm

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07:00:00am

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07:00pm

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07pm

            <time class="value" datetime="2009-06-26">26 July</time>, from
            7pm

            <time class="value" datetime="2009-06-26">26 July</time>, from
            7:00pm

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07:00p.m.

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07:00PM

            <time class="value" datetime="2009-06-26">26 July</time>, from
            7:00am


Meridiem time formats (am pm)

description: h-event


code:
    CPJ Online Press Freedom Summit
    (<time class="dt-start" datetime="2012-10-10">10 Nov 2012</time>) in
    San Francisco.
    Attendees:

Brian Warner

Kyle Machulis

Tantek Çelik

Sid Sutter


value: Brian Warner

value: Kyle Machulis

value: Tantek Çelik

value: Sid Sutter


h-event with attendees

description: h-event


code:
    IndieWebCamp 2012

  from <time class="dt-start">2012-06-30</time>
  to <time class="dt-end">2012-07-01</time> at

    Geoloqi,
    920 SW 3rd Ave. Suite 400,
    Portland,
    OR


value: Geoloqi, 920 SW 3rd Ave. Suite 400, Portland, OR


Event with location

description: h-event


code:
 The 4th Microformat party will be on

  <time class="value" datetime="2009-06-26">26 July</time>, from
  <time class="value">19:00</time> to
 <time class="value">22:00</time>.


Concatenate multiple datetime elements

description: h-event


code:
    The party will be on

      March 14th 2013

        <time class="value" datetime="2013-06-25">25 July</time>, from
        07:00:00am

        <time class="dt-start" datetime="2013-06-26">26 June</time>

        Just added,
        Removed

    June 29
    <data class="dt-start" value="2013-07-01"></data>

2013-07-02


dt-property

description: h-event


Just a hyperlink

description: h-event


Just a name

description: h-event


h-event parsing tests

description: This page was design to test the parsing of h-event. These tests are part of the micorformats 2 test suite.


code:
    The 4th Microformat party will be on

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00:00-08:00</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00:00-0800</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00:00+0800</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00:00Z</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00:00</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00-08:00</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00+08:00</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00Z</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00</time>

            <time class="dt-end" datetime="2013-034">3 February 2013</time>

            <time class="dt-end" datetime="2013-06-27 15:34">26 July 2013</time>


Time formats

description: h-event


The <abbr> Tag Pattern

description: h-geo


code:
My favourite hill in the lakes is

        Pen-y-ghent
        (Geo: 54.155278,
        -2.249722). It
        raises to 694m.


Geo with a altitude property

description: h-geo


The <abbr> tag pattern

description: h-geo


Just a name

description: h-geo


code:
We are meeting at
    The Bricklayer's Arms
    (Geo: 51.513458:
    -0.14812)


Broken into properties

description: h-geo


h-geo parsing tests

description: This page was design to test the parsing of h-geo. These tests are part of the micorformats 2 test suite.


Value-title class pattern

description: h-geo


code:
microformats.org at 7

Last week the microformats.org community
                celebrated its 7th birthday at a gathering hosted by Mozilla in
                San Francisco and recognized accomplishments, challenges, and
                opportunities.

The microformats tagline “humans first, machines second”
                forms the basis of many of our
                principles, and
                in that regard, we’d like to recognize a few people and
                thank them for their years of volunteer service

Updated
            <time class="dt-updated" datetime="2012-06-25T17:08:26">June 25th, 2012</time> by
            Tantek

            San Francisco,
            CA

        (Geo: 37.774921;-122.445202)

            microformats.org

        Publishing policy


value: San Francisco, CA

name: microformats.org at 7 Last week the microformats.org community celebrated its 7th birthday at a gathering hosted by Mozilla in San Francisco and recognized accomplishments, challenges, and opportunities. The microformats tagline “humans first, machines second” forms the basis of many of our principles, and in that regard, we’d like to recognize a few people and thank them for their years of volunteer service Updated June 25th, 2012 by Tantek San Francisco, CA (Geo: 37.774921;-122.445202) microformats.org Publishing policy


With dateline h-card

description: h-news


code:
microformats.org at 7

Last week the microformats.org community
                celebrated its 7th birthday at a gathering hosted by Mozilla in
                San Francisco and recognized accomplishments, challenges, and
                opportunities.

The microformats tagline “humans first, machines second”
                forms the basis of many of our
                principles, and
                in that regard, we’d like to recognize a few people and
                thank them for their years of volunteer service

Updated
            <time class="dt-updated" datetime="2012-06-25T17:08:26">June 25th, 2012</time> by
            Tantek

        microformats.org


name: microformats.org at 7 Last week the microformats.org community celebrated its 7th birthday at a gathering hosted by Mozilla in San Francisco and recognized accomplishments, challenges, and opportunities. The microformats tagline “humans first, machines second” forms the basis of many of our principles, and in that regard, we’d like to recognize a few people and thank them for their years of volunteer service Updated June 25th, 2012 by Tantek microformats.org


Minimum properties

description: h-news


h-news parsing tests

description: This page was design to test the parsing of h-news. These tests are part of the micorformats 2 test suite.


Just a hyperlink

description: h-org


Simple org

description: h-org


Simple properties

description: h-org


h-org parsing tests

description: This page was design to test the parsing of h-org. These tests are part of the micorformats 2 test suite.


code:
Raspberry Pi

The Raspberry Pi is a credit-card sized computer that plugs into your TV and a keyboard. It’s a capable little PC which can be used for many of the things that your desktop PC does, like spreadsheets, word-processing and games. It also plays high-definition video. We want to see it being used by kids all over the world to learn programming.

    More info about the Raspberry Pi

£29.95

            9.2 out of
            10
            based on 178 reviews

Categories: Computer, Education

From:
        The Raspberry Pi Foundation -
        Cambridge
        UK


value: The Raspberry Pi is a credit-card sized computer that plugs into your TV and a keyboard. It’s a capable little PC which can be used for many of the things that your desktop PC does, like spreadsheets, word-processing and games. It also plays high-definition video. We want to see it being used by kids all over the world to learn programming.

value: 9.2 out of 10 based on 178 reviews

category: Computer Education

value: From: The Raspberry Pi Foundation - Cambridge UK


With h-review-aggregate

description: h-product


Just a hyperlink

description: h-product


Just a name

description: h-product


code:
Raspberry Pi

The Raspberry Pi is a credit-card sized computer that plugs into your TV and a keyboard. It’s a capable little PC which can be used for many of the things that your desktop PC does, like spreadsheets, word-processing and games. It also plays high-definition video. We want to see it being used by kids all over the world to learn programming.

    More info about the Raspberry Pi

£29.95

4.5 out of 5

Categories: Computer, Education


value: 4.5 out of 5


With h-review

description: h-product


h-product parsing tests

description: This page was design to test the parsing of h-product. These tests are part of the micorformats 2 test suite.


code:
Yorkshire Puddings

Makes 6 good sized Yorkshire puddings, the way my mum taught me

            4.5 stars out 5 based on
            35 reviews

Ingredients

1 egg

75g plain flour

70ml milk

60ml water

Pinch of salt

Time

Preparation 10 mins

Cook 25 mins

Instructions

Pre-heat oven to 230C or gas mark 8. Pour the vegetable oil evenly into 2 x 4-hole
            Yorkshire pudding tins and place in the oven to heat through.

To make the batter, add all the flour into a bowl and beat in the eggs until smooth.
            Gradually add the milk and water while beating the mixture. It should be smooth and
            without lumps. Finally add a pinch of salt.

Make sure the oil is piping hot before pouring the batter evenly into the tins.
            Place in the oven for 20-25 minutes until pudding have risen and look golden brown

Nutrition

Calories: 125

Fat: 3.2g

Cholesterol: 77mg

(Amount per pudding)

        Published on <time class="dt-published" datetime="2011-10-27">27 Oct 2011</time> by

            Glenn Jones

    Photo by dithie


summary: Makes 6 good sized Yorkshire puddings, the way my mum taught me

value: 4.5 stars out 5 based on 35 reviews

value: 1 egg

html: 1 egg

value: 75g plain flour

html: 75g plain flour

value: 70ml milk

html: 70ml milk

value: 60ml water

html: 60ml water

value: Pinch of salt

html: Pinch of salt

value: Pre-heat oven to 230C or gas mark 8. Pour the vegetable oil evenly into 2 x 4-hole Yorkshire pudding tins and place in the oven to heat through. To make the batter, add all the flour into a bowl and beat in the eggs until smooth. Gradually add the milk and water while beating the mixture. It should be smooth and without lumps. Finally add a pinch of salt. Make sure the oil is piping hot before pouring the batter evenly into the tins. Place in the oven for 20-25 minutes until pudding have risen and look golden brown

nutrition:
Calories: 125
Fat: 3.2g
Cholesterol: 77mg

value: Glenn Jones


Broken into properties

description: h-recipe


code:
Toast

Slice of bread

Butter


value: Slice of bread

html: Slice of bread

value: Butter

html: Butter


Minimum properties

description: h-recipe


h-recipe parsing tests

description: This page was design to test the parsing of h-recipe. These tests are part of the micorformats 2 test suite.


code:
        Tim Berners-Lee,
        invented the World Wide Web.

    Belongs to following groups:


summary: invented the World Wide Web


Affiliations

description: h-resume


code:
Tim Berners-Lee

Invented the World Wide Web.

MIT

            32 Vassar Street,
            Room 32-G524,
            Cambridge,
            MA
            02139,
            USA.

Tel:+1 (617) 253 5702

Email:timbl@w3.org


summary: Invented the World Wide Web.

value: MIT 32 Vassar Street, Room 32-G524, Cambridge, MA 02139, USA. Tel:+1 (617) 253 5702 Email:timbl@w3.org


Contact

description: h-resume


code:
Tim Berners-Lee

Director of the World Wide Web Foundation

Invented the World Wide Web.

        The Queen's College, Oxford University,
        BA Hons (I) Physics
        <time class="dt-start" datetime="1973-09">1973</time> –
        <time class="dt-end" datetime="1976-06">1976</time>


summary: Invented the World Wide Web.

value: Director of the World Wide Web Foundation

value: The Queen's College, Oxford University, BA Hons (I) Physics 1973 - 1976

type: h-event h-card

description: BA Hons (I) Physics

description: BA Hons (I) Physics


Educational experience

description: h-resume


code: Tim Berners-Lee, invented the World Wide Web.


Just a name

description: h-resume


code:
        Tim Berners-Lee,
        invented the World Wide Web.

    Skills:

information systems

advocacy

leadership


summary: invented the World Wide Web

skill:
information systems
advocacy
leadership


Skills

description: h-resume


h-resume parsing tests

description: This page was design to test the parsing of h-resume. These tests are part of the micorformats 2 test suite.


code:
Tim Berners-Lee

Director of the World Wide Web Foundation

Invented the World Wide Web.

Director

World Wide Web Foundation

            <time class="dt-start" datetime="2009-01-18">Jan 2009</time> – Present
            <time class="dt-duration" datetime="P2Y11M">(2 years 11 month)</time>


summary: Invented the World Wide Web.

name: Director of the World Wide Web Foundation

value: Director World Wide Web Foundation Jan 2009 - Present (2 years 11 month)


Work experience

description: h-resume


code:
Fullfrontal

A one day JavaScript Conference held in Brighton

<time class="dt-start" datetime="2012-11-09">9th November 2012</time>

        9.9 out of
        10
        based on 62 reviews


name: Fullfrontal A one day JavaScript Conference held in Brighton 9th November 2012 9.9 out of 10 based on 62 reviews


With p-item as a h-event

description: hreview-aggregate


code:
Mediterranean Wraps

        Customers flock to this small restaurant for their
        tasty falafel and shawerma wraps and welcoming staff.

    4.5 out of 5


value: Mediterranean Wraps

name: Mediterranean Wraps Customers flock to this small restaurant for their tasty falafel and shawerma wraps and welcoming staff. 4.5 out of 5


Minimum properties

description: h-review-aggregate


code:
Mediterranean Wraps

            433 S California Ave,
            Palo Alto,
            CA -
            (650) 321-8189

    Customers flock to this small restaurant for their
    tasty falafel and shawerma wraps and welcoming staff.

        9.2 out of
        10
        based on 17 reviews


name: Mediterranean Wraps 433 S California Ave, Palo Alto, CA - (650) 321-8189 Customers flock to this small restaurant for their tasty falafel and shawerma wraps and welcoming staff. 9.2 out of 10 based on 17 reviews


Broken into properties

description: h-review-aggregate


h-review-aggregate parsing tests

description: This page was design to test the parsing of h-review-aggregate. These tests are part of the micorformats 2 test suite.


Just a hyperlink

description: h-review


code:
    Crepes on Cole

4.7 out of 5 stars


With implied item name and url

description: h-review


code:
        Crepes on Cole

5 out of 5 stars


With item

description: h-review


Just a name

description: h-review


code: <img class="h-review" src="images/photo.gif" alt="Crepes on Cole" />


Just a photo

description: h-review


h-review parsing tests

description: This page was design to test the parsing of h-review. These tests are part of the micorformats 2 test suite.


code:
    5 out of 5 stars

Crepes on Cole is awesome

        Reviewer: Tantek -

    <time class="dt-reviewed" datetime="2005-04-18">April 18, 2005</time>

        Crepes on Cole is one of the best little
        creperies in San Francisco.
        Excellent food and service. Plenty of tables in a variety of sizes
        for parties large and small.  Window seating makes for excellent
        people watching to/from the N-Judah which stops right outside.
        I've had many fun social gatherings here, as well as gotten
        plenty of work done thanks to neighborhood WiFi.

Visit date: April 2005

Food eaten: crepe

Permanent link for review: http://example.com/crepe

Creative Commons Attribution-ShareAlike License


value: Reviewer: Tantek -

value: Crepes on Cole is one of the best little creperies in San Francisco. Excellent food and service. Plenty of tables in a variety of sizes for parties large and small. Window seating makes for excellent people watching to/from the N-Judah which stops right outside. I've had many fun social gatherings here, as well as gotten plenty of work done thanks to neighborhood WiFi.

value: San Francisco


With vcard item

description: h-review


code:
    The 4th Microformat party will be on

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07:00:00pm

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07:00:00am

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07:00pm

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07pm

            <time class="value" datetime="2009-06-26">26 July</time>, from
            7pm

            <time class="value" datetime="2009-06-26">26 July</time>, from
            7:00pm

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07:00p.m.

            <time class="value" datetime="2009-06-26">26 July</time>, from
            07:00PM

            <time class="value" datetime="2009-06-26">26 July</time>, from
            7:00am


Meridiem time formats (am pm)

description: hcalendar


code:
    CPJ Online Press Freedom Summit
    (<time class="dtstart" datetime="2012-10-10">10 Nov 2012</time>) in
    San Francisco.
    Attendees:

Brian Warner

Kyle Machulis

Tantek Çelik

Sid Sutter


value: Brian Warner

value: Kyle Machulis

value: Tantek Çelik

value: Sid Sutter


hcalendar with attendees

description: hcalendar


code:
    IndieWebCamp 2012

  from <time class="dtstart">2012-06-30</time>
  to <time class="dtend">2012-07-01</time> at

    Geoloqi,

        920 SW 3rd Ave. Suite 400,
        Portland,
        OR


value: Geoloqi, 920 SW 3rd Ave. Suite 400, Portland, OR

value: 920 SW 3rd Ave. Suite 400, Portland, OR


Event with location

description: hcalendar


code:
 The 4th Microformat party will be on

  <time class="value" datetime="2009-06-26">26 July</time>, from
  <time class="value">19:00</time> to
 <time class="value">22:00</time>.


Concatenate multiple datetime elements

description: hcalendar


Just a hyperlink

description: hcalendar


Just a name

description: hcalendar


hcalendar parsing tests

description: This page was design to test the parsing of hcalendar and its output to the newer JSON structure of micorformats 2. These tests are part of the micorformats 2 test suite.


code:
    The 4th Microformat party will be on

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00:00-08:00</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00:00-0800</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00:00+0800</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00:00Z</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00:00</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00-08:00</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00+08:00</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00Z</time>

            <time class="value" datetime="2009-06-26">26 July</time>, from
            <time class="value">19:00</time>

            <time class="dtend" datetime="2013-034">3 February 2013</time>


Time formats

description: hcalendar


code:
    John Doe

notthis@example.com

                internet
                notthis@example.com

notthis@example.com

john@example.com


Emails

description: hcard


Class attribute format

description: hcard


A hyperlinked photo

description: hcard


Just a hyperlink

description: hcard


Just a name

description: hcard


code:
John Doe

    Pronunciation of my name

Nicknames:

Man with no name

Lost boy

About:

John Doe is one of those names you always have issues with.

It can be a real problem booking a hotel room with the name John Doe.

Companies:

Madgex Creative Director

Web Feet Media Ltd Owner

Tags:
    design,
    development and
    web

Phone numbers:

            Work (preferred):
            +1 415 555 100

Home: +1 415 555 200

Postal: +1 415 555 300

Emails:

John Doe at Madgex

John Doe at Web Feet Media

John Doe uses PigeonMail 2.1 or Outlook 2007 for email.

Addresses:

                Work:
                North Street,
                Brighton,
                United Kingdom

                Home:
                West Street,
                Brighton,
                United Kingdom

In emergency contact: Jane Doe or Dave Doe.

Key: hd02$Gfu*d%dh87KTa2=23934532479


nickname:
Man with no name
Lost boy

note: John Doe is one of those names you always have issues with.

note: It can be a real problem booking a hotel room with the name John Doe.

org:
Madgex
Web Feet Media Ltd

title:
Creative Director
Owner

category: design development web

mailer:
PigeonMail 2.1
Outlook 2007

value: Work: North Street, Brighton, United Kingdom

value: Home: West Street, Brighton, United Kingdom

value: Dave Doe


Multiple occurrence properties

description: hcard


code:
        Dr
        John
        P
        Doe
        <data class="honorific-suffix" value="MSc"></data>


Name properties

description: hcard


code:
John Doe

Birthday: January 1st, 2000

Role: Designer

Location: Brighton

Time zone: Eastern Standard Time

Profile details:

Profile id: http://example.com/profiles/johndoe

Details are: Public

Last updated: January 1st, 2008 - 13:45


Single occurrence properties

description: hcard


hcard parsing tests

description: This page was design to test the parsing of hcard and its output to the newer JSON structure of micorformats 2. These tests are part of the micorformats 2 test suite.


Just a hyperlink

description: hentry


Just a name

description: hentry


hentry parsing tests

description: This page was design to test the parsing of hentry and its output to the newer JSON structure of micorformats 2. These tests are part of the micorformats 2 test suite.


code:
microformats.org at 7

Last week the microformats.org community
            celebrated its 7th birthday at a gathering hosted by Mozilla in
            San Francisco and recognized accomplishments, challenges, and
            opportunities.

The microformats tagline “humans first, machines second”
            forms the basis of many of our
            principles, and
            in that regard, we’d like to recognize a few people and
            thank them for their years of volunteer service

Updated
        <time class="updated" datetime="2012-06-25T17:08:26">June 25th, 2012</time> by
        Tantek


value: Last week the microformats.org community celebrated its 7th birthday at a gathering hosted by Mozilla in San Francisco and recognized accomplishments, challenges, and opportunities. The microformats tagline “humans first, machines second” forms the basis of many of our principles, and in that regard, we’d like to recognize a few people and thank them for their years of volunteer service

value: Tantek


Entry with summary and content

description: hentry


code:
microformats.org at 7

Last week the microformats.org community
                celebrated its 7th birthday at a gathering hosted by Mozilla in
                San Francisco and recognized accomplishments, challenges, and
                opportunities.

The microformats tagline “humans first, machines second”
                forms the basis of many of our
                principles, and
                in that regard, we’d like to recognize a few people and
                thank them for their years of volunteer service

Updated
            <time class="updated" datetime="2012-06-25T17:08:26">June 25th, 2012</time> by
            Tantek

                San Francisco,
                CA

        (Geo: 37.774921;-122.445202)

            microformats.org

        Publishing policy