summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorDries2013-06-19 20:36:24 (GMT)
committerDries2013-06-19 20:36:24 (GMT)
commit0eaa35d578509454b182e24b0bc341ff66106aec (patch)
treec435bf53b58d87152f4fb3efcc41d95499403048 /core
parente4c24df2f3a2853f57dfe6828b1331746b011fd8 (diff)
Issue #1839468 by ParisLiakos, damiankloip, dawehner, jibran: Replace aggregator rss parsing with Zend Feed.
Diffstat (limited to 'core')
-rw-r--r--core/core.services.yml54
-rw-r--r--core/includes/common.inc6
-rw-r--r--core/lib/Drupal/Component/Bridge/ZfExtensionManagerSfContainer.php95
-rw-r--r--core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php366
-rw-r--r--core/modules/aggregator/lib/Drupal/aggregator/Tests/FeedParserTest.php7
-rw-r--r--core/vendor/autoload.php2
-rw-r--r--core/vendor/composer/ClassLoader.php4
-rw-r--r--core/vendor/composer/autoload_namespaces.php3
-rw-r--r--core/vendor/composer/autoload_real.php6
-rw-r--r--core/vendor/composer/installed.json828
-rw-r--r--core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/.travis.yml1
-rw-r--r--core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/CHANGELOG.md10
-rw-r--r--core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/composer.json8
-rw-r--r--core/vendor/zendframework/zend-escaper/Zend/Escaper/Escaper.php390
-rw-r--r--core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/ExceptionInterface.php13
-rw-r--r--core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/InvalidArgumentException.php18
-rw-r--r--core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/RuntimeException.php18
-rw-r--r--core/vendor/zendframework/zend-escaper/Zend/Escaper/README.md15
-rw-r--r--core/vendor/zendframework/zend-escaper/Zend/Escaper/composer.json24
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Exception/BadMethodCallException.php15
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Exception/ExceptionInterface.php13
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Exception/InvalidArgumentException.php15
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Exception/RuntimeException.php15
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/AbstractCallback.php291
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/CallbackInterface.php51
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/ExceptionInterface.php15
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/InvalidArgumentException.php17
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/RuntimeException.php17
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/HttpResponse.php211
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/AbstractModel.php39
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/Subscription.php142
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/SubscriptionPersistenceInterface.php47
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/PubSubHubbub.php147
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Publisher.php397
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Subscriber.php837
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Subscriber/Callback.php316
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Version.php15
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/README.md15
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/AbstractEntry.php224
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/AbstractFeed.php300
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection.php17
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/AbstractCollection.php25
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Author.php29
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Category.php35
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Collection.php17
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/AbstractEntry.php230
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/Atom.php370
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/EntryInterface.php129
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/Rss.php599
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/BadMethodCallException.php17
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/ExceptionInterface.php15
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/InvalidArgumentException.php17
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/RuntimeException.php17
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/AbstractEntry.php233
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/AbstractFeed.php176
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Atom/Entry.php628
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Atom/Feed.php536
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Content/Entry.php37
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php73
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php71
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/DublinCore/Entry.php238
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/DublinCore/Feed.php281
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Podcast/Entry.php180
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Podcast/Feed.php277
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Slash/Entry.php121
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Syndication/Feed.php149
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Thread/Entry.php72
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/WellFormedWeb/Entry.php50
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionManager.php80
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionManagerInterface.php29
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionPluginManager.php77
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/AbstractFeed.php307
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Atom.php410
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Atom/Source.php94
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/FeedInterface.php111
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Rss.php709
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/FeedSet.php127
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Http/ClientInterface.php21
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Http/ResponseInterface.php27
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Reader.php674
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Uri.php184
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/AbstractFeed.php848
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Deleted.php237
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Entry.php767
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/BadMethodCallException.php22
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/ExceptionInterface.php19
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/InvalidArgumentException.php22
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/RuntimeException.php17
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/AbstractRenderer.php164
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Atom/Renderer/Feed.php109
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Content/Renderer/Entry.php76
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/DublinCore/Renderer/Entry.php80
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/DublinCore/Renderer/Feed.php80
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Entry.php246
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Feed.php362
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Renderer/Entry.php200
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Renderer/Feed.php304
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/RendererInterface.php49
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Slash/Renderer/Entry.php75
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Threading/Renderer/Entry.php129
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/WellFormedWeb/Renderer/Entry.php80
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionManager.php80
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionManagerInterface.php29
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionPluginManager.php80
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Feed.php241
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/FeedFactory.php127
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/AbstractRenderer.php233
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/Entry/Atom.php427
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/Entry/Atom/Deleted.php102
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/Entry/AtomDeleted.php104
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/Entry/Rss.php329
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/Feed/AbstractAtom.php403
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/Feed/Atom.php96
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/Feed/Atom/AbstractAtom.php400
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/Feed/Atom/Source.php91
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/Feed/AtomSource.php95
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/Feed/Rss.php484
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/RendererInterface.php100
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Source.php16
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Version.php15
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Writer.php199
-rw-r--r--core/vendor/zendframework/zend-feed/Zend/Feed/composer.json31
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/AbstractOptions.php161
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/ArrayObject.php34
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/ArrayObject/PhpLegacyCompatibility.php35
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/ArrayObject/PhpReferenceCompatibility.php433
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/ArraySerializableInterface.php28
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/ArrayStack.php33
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/ArrayUtils.php275
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/CallbackHandler.php218
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/DateTime.php47
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/DispatchableInterface.php25
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/ErrorHandler.php115
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Exception/BadMethodCallException.php17
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Exception/DomainException.php17
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Exception/ExceptionInterface.php17
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Exception/ExtensionNotLoadedException.php17
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Exception/InvalidArgumentException.php17
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Exception/InvalidCallbackException.php17
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Exception/LogicException.php17
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Exception/RuntimeException.php17
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Glob.php205
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/AbstractHydrator.php198
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Aggregate/AggregateHydrator.php87
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Aggregate/ExtractEvent.php99
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Aggregate/HydrateEvent.php85
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Aggregate/HydratorListener.php81
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/ArraySerializable.php77
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/ClassMethods.php190
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Filter/FilterComposite.php198
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Filter/FilterInterface.php21
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Filter/FilterProviderInterface.php19
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Filter/GetFilter.php27
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Filter/HasFilter.php27
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Filter/IsFilter.php27
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Filter/MethodMatchFilter.php48
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Filter/NumberOfParameterFilter.php54
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/HydratorAwareInterface.php28
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/HydratorInterface.php30
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/HydratorOptionsInterface.php19
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/HydratorPluginManager.php56
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/ObjectProperty.php71
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Reflection.php92
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Strategy/ClosureStrategy.php100
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Strategy/DefaultStrategy.php35
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Strategy/SerializableStrategy.php123
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/Strategy/StrategyInterface.php29
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Hydrator/StrategyEnabledInterface.php48
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/InitializableInterface.php23
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Message.php118
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/MessageInterface.php45
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/ParameterObjectInterface.php38
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Parameters.php115
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/ParametersInterface.php86
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/PriorityQueue.php302
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/README.md15
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Request.php15
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/RequestInterface.php14
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/Response.php15
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/ResponseInterface.php15
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/SplPriorityQueue.php93
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/SplQueue.php55
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/SplStack.php55
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/StringUtils.php189
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/StringWrapper/AbstractStringWrapper.php272
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/StringWrapper/Iconv.php289
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/StringWrapper/Intl.php83
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/StringWrapper/MbString.php121
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/StringWrapper/Native.php134
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/StringWrapper/StringWrapperInterface.php111
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/compatibility/autoload.php14
-rw-r--r--core/vendor/zendframework/zend-stdlib/Zend/Stdlib/composer.json28
192 files changed, 25231 insertions, 692 deletions
diff --git a/core/core.services.yml b/core/core.services.yml
index 03b8c7c..50775db 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -465,3 +465,57 @@ services:
date:
class: Drupal\Core\Datetime\Date
arguments: ['@config.factory', '@language_manager']
+ feed.bridge.reader:
+ class: Drupal\Component\Bridge\ZfExtensionManagerSfContainer
+ calls:
+ - [setContainer, ['@service_container']]
+ arguments: ['feed.reader.']
+ feed.bridge.writer:
+ class: Drupal\Component\Bridge\ZfExtensionManagerSfContainer
+ calls:
+ - [setContainer, ['@service_container']]
+ arguments: ['feed.writer.']
+# Zend Feed reader plugins
+ feed.reader.dublincoreentry:
+ class: Zend\Feed\Reader\Extension\DublinCore\Entry
+ feed.reader.dublincorefeed:
+ class: Zend\Feed\Reader\Extension\DublinCore\Feed
+ feed.reader.contententry:
+ class: Zend\Feed\Reader\Extension\Content\Entry
+ feed.reader.atomentry:
+ class: Zend\Feed\Reader\Extension\Atom\Entry
+ feed.reader.atomfeed:
+ class: Zend\Feed\Reader\Extension\Atom\Feed
+ feed.reader.slashentry:
+ class: Zend\Feed\Reader\Extension\Slash\Entry
+ feed.reader.wellformedwebentry:
+ class: Zend\Feed\Reader\Extension\WellFormedWeb\Entry
+ feed.reader.threadentry:
+ class: Zend\Feed\Reader\Extension\Thread\Entry
+ feed.reader.podcastentry:
+ class: Zend\Feed\Reader\Extension\Podcast\Entry
+ feed.reader.podcastfeed:
+ class: Zend\Feed\Reader\Extension\Podcast\Feed
+# Zend Feed writer plugins
+ feed.writer.atomrendererfeed:
+ class: Zend\Feed\Writer\Extension\Atom\Renderer\Feed
+ feed.writer.contentrendererentry:
+ class: Zend\Feed\Writer\Extension\Content\Renderer\Entry
+ feed.writer.dublincorerendererentry:
+ class: Zend\Feed\Writer\Extension\DublinCore\Renderer\Entry
+ feed.writer.dublincorerendererfeed:
+ class: Zend\Feed\Writer\Extension\DublinCore\Renderer\Feed
+ feed.writer.itunesentry:
+ class: Zend\Feed\Writer\Extension\ITunes\Entry
+ feed.writer.itunesfeed:
+ class: Zend\Feed\Writer\Extension\ITunes\Feed
+ feed.writer.itunesrendererentry:
+ class: Zend\Feed\Writer\Extension\ITunes\Renderer\Entry
+ feed.writer.itunesrendererfeed:
+ class: Zend\Feed\Writer\Extension\ITunes\Renderer\Feed
+ feed.writer.slashrendererentry:
+ class: Zend\Feed\Writer\Extension\Slash\Renderer\Entry
+ feed.writer.threadingrendererentry:
+ class: Zend\Feed\Writer\Extension\Threading\Renderer\Entry
+ feed.writer.wellformedwebrendererentry:
+ class: Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry
diff --git a/core/includes/common.inc b/core/includes/common.inc
index d8638fe..a392a5a 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -22,6 +22,8 @@ use Drupal\Core\Database\Database;
use Drupal\Core\Routing\GeneratorNotInitializedException;
use Drupal\Core\SystemListingInfo;
use Drupal\Core\Template\Attribute;
+use Zend\Feed\Writer\Writer;
+use Zend\Feed\Reader\Reader;
/**
* @file
@@ -3988,6 +3990,10 @@ function _drupal_bootstrap_code() {
// Load all enabled modules
Drupal::moduleHandler()->loadAll();
+ // Set our bridge extension manager to Zend Feed.
+ Reader::setExtensionManager(Drupal::service('feed.bridge.reader'));
+ Writer::setExtensionManager(Drupal::service('feed.bridge.writer'));
+
// Make sure all stream wrappers are registered.
file_get_stream_wrappers();
diff --git a/core/lib/Drupal/Component/Bridge/ZfExtensionManagerSfContainer.php b/core/lib/Drupal/Component/Bridge/ZfExtensionManagerSfContainer.php
new file mode 100644
index 0000000..94d969b
--- /dev/null
+++ b/core/lib/Drupal/Component/Bridge/ZfExtensionManagerSfContainer.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\Bridge\ZfExtensionManagerSfContainer
+ */
+namespace Drupal\Component\Bridge;
+
+use Symfony\Component\DependencyInjection\ContainerAwareInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Zend\Feed\Reader\ExtensionManagerInterface as ReaderManagerInterface;
+use Zend\Feed\Writer\ExtensionManagerInterface as WriterManagerInterface;
+
+/**
+ * Defines a bridge between the ZF2 service manager to Symfony container.
+ */
+class ZfExtensionManagerSfContainer implements ReaderManagerInterface, WriterManagerInterface, ContainerAwareInterface {
+
+ /**
+ * This property was based from Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ *
+ * A map of characters to be replaced through strtr.
+ *
+ * @var array
+ *
+ * @see \Drupal\Component\Bridge\ZfExtensionManagerSfContainer::canonicalizeName().
+ */
+ protected $canonicalNamesReplacements = array('-' => '', '_' => '', ' ' => '', '\\' => '', '/' => '');
+
+ /**
+ * The prefix to be used when retrieving plugins from the container.
+ *
+ * @var string
+ */
+ protected $prefix = '';
+
+ /**
+ * Constructs a ZfExtensionManagerSfContainer object.
+ *
+ * @param string $prefix
+ * The prefix to be used when retrieving plugins from the container.
+ */
+ public function __construct($prefix = '') {
+ return $this->prefix = $prefix;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($extension) {
+ return $this->container->get($this->prefix . $this->canonicalizeName($extension));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($extension) {
+ return $this->container->has($this->prefix . $this->canonicalizeName($extension));
+ }
+
+ /**
+ * This method was based from Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ *
+ * Canonicalize the extension name to a service name.
+ *
+ * @param string $name
+ * The extension name.
+ *
+ * @return string
+ * The service name, without the prefix.
+ */
+ protected function canonicalizeName($name) {
+ if (isset($this->canonicalNames[$name])) {
+ return $this->canonicalNames[$name];
+ }
+ // This is just for performance instead of using str_replace().
+ return $this->canonicalNames[$name] = strtolower(strtr($name, $this->canonicalNamesReplacements));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setContainer(ContainerInterface $container = NULL) {
+ $this->container = $container;
+ }
+
+}
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php
index eab6e9b..a295749 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php
@@ -11,6 +11,9 @@ use Drupal\aggregator\Plugin\ParserInterface;
use Drupal\aggregator\Plugin\Core\Entity\Feed;
use Drupal\aggregator\Annotation\AggregatorParser;
use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Cache\Cache;
+use Zend\Feed\Reader\Reader;
+use Zend\Feed\Reader\Exception\ExceptionInterface;
/**
* Defines a default parser implementation.
@@ -26,353 +29,50 @@ use Drupal\Core\Annotation\Translation;
class DefaultParser implements ParserInterface {
/**
- * The extracted channel info.
- *
- * @var array
- */
- protected $channel = array();
-
- /**
- * The extracted image info.
- *
- * @var array
- */
- protected $image = array();
-
- /**
- * The extracted items.
- *
- * @var array
- */
- protected $items = array();
-
- /**
- * The element that is being processed.
- *
- * @var array
- */
- protected $element = array();
-
- /**
- * The tag that is being processed.
- *
- * @var string
- */
- protected $tag = '';
-
- /**
- * Key that holds the number of processed "entry" and "item" tags.
- *
- * @var int
- */
- protected $item;
-
- /**
- * Implements \Drupal\aggregator\Plugin\ParserInterface::parse().
+ * {@inheritdoc}
*/
public function parse(Feed $feed) {
- // Filter the input data.
- if ($this->parseFeed($feed->source_string, $feed)) {
-
- // Prepare the channel data.
- foreach ($this->channel as $key => $value) {
- $this->channel[$key] = trim($value);
- }
-
- // Prepare the image data (if any).
- foreach ($this->image as $key => $value) {
- $this->image[$key] = trim($value);
- }
-
- // Add parsed data to the feed object.
- $feed->link->value = !empty($channel['link']) ? $channel['link'] : '';
- $feed->description->value = !empty($channel['description']) ? $channel['description'] : '';
- $feed->image->value = !empty($image['url']) ? $image['url'] : '';
-
- // Clear the page and block caches.
- cache_invalidate_tags(array('content' => TRUE));
-
- return TRUE;
+ try {
+ $channel = Reader::importString($feed->source_string);
}
+ catch (ExceptionInterface $e) {
+ watchdog_exception('aggregator', $e);
+ drupal_set_message(t('The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $e->getMessage())), 'error');
- return FALSE;
- }
-
-
- /**
- * Parses a feed and stores its items.
- *
- * @param string $data
- * The feed data.
- * @param \Drupal\aggregator\Plugin\Core\Entity\Feed $feed
- * An object describing the feed to be parsed.
- *
- * @return bool
- * FALSE on error, TRUE otherwise.
- */
- protected function parseFeed(&$data, Feed $feed) {
- // Parse the data.
- $xml_parser = drupal_xml_parser_create($data);
- xml_set_element_handler($xml_parser, array($this, 'elementStart'), array($this, 'elementEnd'));
- xml_set_character_data_handler($xml_parser, array($this, 'elementData'));
-
- if (!xml_parse($xml_parser, $data, 1)) {
- watchdog('aggregator', 'The feed from %site seems to be broken due to an error "%error" on line %line.', array('%site' => $feed->label(), '%error' => xml_error_string(xml_get_error_code($xml_parser)), '%line' => xml_get_current_line_number($xml_parser)), WATCHDOG_WARNING);
- drupal_set_message(t('The feed from %site seems to be broken because of error "%error" on line %line.', array('%site' => $feed->label(), '%error' => xml_error_string(xml_get_error_code($xml_parser)), '%line' => xml_get_current_line_number($xml_parser))), 'error');
return FALSE;
}
- xml_parser_free($xml_parser);
-
- // We reverse the array such that we store the first item last, and the last
- // item first. In the database, the newest item should be at the top.
- $this->items = array_reverse($this->items);
+ $feed->link->value = $channel->getLink();
+ $feed->description->value = $channel->getDescription();
+ if ($image = $channel->getImage()) {
+ $feed->image->value = $image['uri'];
+ }
// Initialize items array.
$feed->items = array();
- foreach ($this->items as $item) {
-
- // Prepare the item:
- foreach ($item as $key => $value) {
- $item[$key] = trim($value);
- }
-
- // Resolve the item's title. If no title is found, we use up to 40
- // characters of the description ending at a word boundary, but not
- // splitting potential entities.
- if (!empty($item['title'])) {
- $item['title'] = $item['title'];
- }
- elseif (!empty($item['description'])) {
- $item['title'] = preg_replace('/^(.*)[^\w;&].*?$/', "\\1", truncate_utf8($item['description'], 40));
- }
- else {
- $item['title'] = '';
- }
-
- // Resolve the items link.
- if (!empty($item['link'])) {
- $item['link'] = $item['link'];
+ foreach ($channel as $item) {
+ // Reset the parsed item.
+ $parsed_item = array();
+ // Move the values to an array as expected by processors.
+ $parsed_item['title'] = $item->getTitle();
+ $parsed_item['guid'] = $item->getId();
+ $parsed_item['link'] = $item->getLink();
+ $parsed_item['description'] = $item->getDescription();
+ $parsed_item['author'] = '';
+ if ($author = $item->getAuthor()) {
+ $parsed_item['author'] = $author['name'];
+ }
+ $parsed_item['timestamp'] = '';
+ if ($date = $item->getDateModified()) {
+ $parsed_item['timestamp'] = $date->getTimestamp();
}
- else {
- $item['link'] = $feed->link->value;
- }
-
- // Atom feeds have an ID tag instead of a GUID tag.
- if (!isset($item['guid'])) {
- $item['guid'] = isset($item['id']) ? $item['id'] : '';
- }
-
- // Atom feeds have a content and/or summary tag instead of a description tag.
- if (!empty($item['content:encoded'])) {
- $item['description'] = $item['content:encoded'];
- }
- elseif (!empty($item['summary'])) {
- $item['description'] = $item['summary'];
- }
- elseif (!empty($item['content'])) {
- $item['description'] = $item['content'];
- }
-
- // Try to resolve and parse the item's publication date.
- $date = '';
- foreach (array('pubdate', 'dc:date', 'dcterms:issued', 'dcterms:created', 'dcterms:modified', 'issued', 'created', 'modified', 'published', 'updated') as $key) {
- if (!empty($item[$key])) {
- $date = $item[$key];
- break;
- }
- }
-
- $item['timestamp'] = strtotime($date);
-
- if ($item['timestamp'] === FALSE) {
- $item['timestamp'] = $this->parseW3cdtf($date); // Aggregator_parse_w3cdtf() returns FALSE on failure.
- }
-
- // Resolve dc:creator tag as the item author if author tag is not set.
- if (empty($item['author']) && !empty($item['dc:creator'])) {
- $item['author'] = $item['dc:creator'];
- }
-
- $item += array('author' => '', 'description' => '');
-
// Store on $feed object. This is where processors will look for parsed items.
- $feed->items[] = $item;
- }
-
- return TRUE;
- }
-
- /**
- * XML parser callback: Perform an action when an opening tag is encountered.
- *
- * @param resource $parser
- * A reference to the XML parser calling the handler.
- * @param string $name
- * The name of the element for which this handler is called.
- * @param array $attributes
- * An associative array with the element's attributes (if any).
- */
- protected function elementStart($parser, $name, $attributes) {
- $name = strtolower($name);
- switch ($name) {
- case 'image':
- case 'textinput':
- case 'summary':
- case 'tagline':
- case 'subtitle':
- case 'logo':
- case 'info':
- $this->element = $name;
- break;
- case 'id':
- case 'content':
- if ($this->element != 'item') {
- $this->element = $name;
- }
- case 'link':
- // According to RFC 4287, link elements in Atom feeds without a 'rel'
- // attribute should be interpreted as though the relation type is
- // "alternate".
- if (!empty($attributes['HREF']) && (empty($attributes['REL']) || $attributes['REL'] == 'alternate')) {
- if ($this->element == 'item') {
- $this->items[$this->item]['link'] = $attributes['HREF'];
- }
- else {
- $this->channel['link'] = $attributes['HREF'];
- }
- }
- break;
- case 'item':
- $this->element = $name;
- $this->item += 1;
- break;
- case 'entry':
- $this->element = 'item';
- $this->item += 1;
- break;
+ $feed->items[] = $parsed_item;
}
- $this->tag = $name;
- }
-
- /**
- * XML parser callback: Perform an action when a closing tag is encountered.
- *
- * @param resource $parser
- * A reference to the XML parser calling the handler.
- * @param string $name
- * The name of the element for which this handler is called.
- * @param array $attributes
- * An associative array with the element's attributes (if any).
- */
- protected function elementEnd($parser, $name) {
- switch ($name) {
- case 'image':
- case 'textinput':
- case 'item':
- case 'entry':
- case 'info':
- $this->element = '';
- break;
- case 'id':
- case 'content':
- if ($this->element == $name) {
- $this->element = '';
- }
- }
- }
+ // Clear the page and block caches.
+ Cache::invalidateTags(array('content' => TRUE));
- /**
- * XML parser callback: Perform an action when data is encountered.
- *
- * @param resource $parser
- * A reference to the XML parser calling the handler.
- * @param string $name
- * The name of the element for which this handler is called.
- * @param array $attributes
- * An associative array with the element's attributes (if any).
- */
- function elementData($parser, $data) {
- $this->items += array($this->item => array());
- switch ($this->element) {
- case 'item':
- $this->items[$this->item] += array($this->tag => '');
- $this->items[$this->item][$this->tag] .= $data;
- break;
- case 'image':
- case 'logo':
- $this->image += array($this->tag => '');
- $this->image[$this->tag] .= $data;
- break;
- case 'link':
- if ($data) {
- $this->items[$this->item] += array($tag => '');
- $this->items[$this->item][$this->tag] .= $data;
- }
- break;
- case 'content':
- $this->items[$this->item] += array('content' => '');
- $this->items[$this->item]['content'] .= $data;
- break;
- case 'summary':
- $this->items[$this->item] += array('summary' => '');
- $this->items[$this->item]['summary'] .= $data;
- break;
- case 'tagline':
- case 'subtitle':
- $this->channel += array('description' => '');
- $this->channel['description'] .= $data;
- break;
- case 'info':
- case 'id':
- case 'textinput':
- // The sub-element is not supported. However, we must recognize
- // it or its contents will end up in the item array.
- break;
- default:
- $this->channel += array($this->tag => '');
- $this->channel[$this->tag] .= $data;
- }
+ return TRUE;
}
- /**
- * Parses the W3C date/time format, a subset of ISO 8601.
- *
- * PHP date parsing functions do not handle this format. See
- * http://www.w3.org/TR/NOTE-datetime for more information. Originally from
- * MagpieRSS (http://magpierss.sourceforge.net/).
- *
- * @param string $date_str
- * A string with a potentially W3C DTF date.
- *
- * @return int|false
- * A timestamp if parsed successfully or FALSE if not.
- */
- function parseW3cdtf($date_str) {
- if (preg_match('/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/', $date_str, $match)) {
- list($year, $month, $day, $hours, $minutes, $seconds) = array($match[1], $match[2], $match[3], $match[4], $match[5], $match[6]);
- // Calculate the epoch for current date assuming GMT.
- $epoch = gmmktime($hours, $minutes, $seconds, $month, $day, $year);
- if ($match[10] != 'Z') { // Z is zulu time, aka GMT
- list($tz_mod, $tz_hour, $tz_min) = array($match[8], $match[9], $match[10]);
- // Zero out the variables.
- if (!$tz_hour) {
- $tz_hour = 0;
- }
- if (!$tz_min) {
- $tz_min = 0;
- }
- $offset_secs = (($tz_hour * 60) + $tz_min) * 60;
- // Is timezone ahead of GMT? If yes, subtract offset.
- if ($tz_mod == '+') {
- $offset_secs *= -1;
- }
- $epoch += $offset_secs;
- }
- return $epoch;
- }
- else {
- return FALSE;
- }
- }
}
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Tests/FeedParserTest.php b/core/modules/aggregator/lib/Drupal/aggregator/Tests/FeedParserTest.php
index 5f4f9f9..bdbe11f 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Tests/FeedParserTest.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Tests/FeedParserTest.php
@@ -7,6 +7,8 @@
namespace Drupal\aggregator\Tests;
+use Zend\Feed\Reader\Reader;
+
/**
* Tests feed parsing in the Aggregator module.
*/
@@ -25,6 +27,11 @@ class FeedParserTest extends AggregatorTestBase {
// feeds have hardcoded dates in them (which may be expired when this test
// is run).
config('aggregator.settings')->set('items.expire', AGGREGATOR_CLEAR_NEVER)->save();
+ // Reset any reader cache between tests.
+ Reader::reset();
+ // Set our bridge extension manager to Zend Feed.
+ $bridge = $this->container->get('feed.bridge.reader');
+ Reader::setExtensionManager($bridge);
}
/**
diff --git a/core/vendor/autoload.php b/core/vendor/autoload.php
index ebc5b04..51fea2c 100644
--- a/core/vendor/autoload.php
+++ b/core/vendor/autoload.php
@@ -4,4 +4,4 @@
require_once __DIR__ . '/composer' . '/autoload_real.php';
-return ComposerAutoloaderInitc269e792cec97d4c278bb968546f51b4::getLoader();
+return ComposerAutoloaderInit4ae4005bb4ec82f3372265feb7e84f37::getLoader();
diff --git a/core/vendor/composer/ClassLoader.php b/core/vendor/composer/ClassLoader.php
index ef99245..1db8d9a 100644
--- a/core/vendor/composer/ClassLoader.php
+++ b/core/vendor/composer/ClassLoader.php
@@ -121,8 +121,8 @@ class ClassLoader
/**
* Registers a set of classes, replacing any others previously set.
*
- * @param string $prefix The classes prefix
- * @param array|string $paths The location(s) of the classes
+ * @param string $prefix The classes prefix
+ * @param array|string $paths The location(s) of the classes
*/
public function set($prefix, $paths)
{
diff --git a/core/vendor/composer/autoload_namespaces.php b/core/vendor/composer/autoload_namespaces.php
index 3385df1..87cf570 100644
--- a/core/vendor/composer/autoload_namespaces.php
+++ b/core/vendor/composer/autoload_namespaces.php
@@ -6,6 +6,9 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname(dirname($vendorDir));
return array(
+ 'Zend\\Stdlib\\' => array($vendorDir . '/zendframework/zend-stdlib'),
+ 'Zend\\Feed\\' => array($vendorDir . '/zendframework/zend-feed'),
+ 'Zend\\Escaper\\' => array($vendorDir . '/zendframework/zend-escaper'),
'Twig_' => array($vendorDir . '/twig/twig/lib'),
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
'Symfony\\Component\\Validator\\' => array($vendorDir . '/symfony/validator'),
diff --git a/core/vendor/composer/autoload_real.php b/core/vendor/composer/autoload_real.php
index 843e1e8..7d1d4ad 100644
--- a/core/vendor/composer/autoload_real.php
+++ b/core/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
// autoload_real.php generated by Composer
-class ComposerAutoloaderInitc269e792cec97d4c278bb968546f51b4
+class ComposerAutoloaderInit4ae4005bb4ec82f3372265feb7e84f37
{
private static $loader;
@@ -19,9 +19,9 @@ class ComposerAutoloaderInitc269e792cec97d4c278bb968546f51b4
return self::$loader;
}
- spl_autoload_register(array('ComposerAutoloaderInitc269e792cec97d4c278bb968546f51b4', 'loadClassLoader'), true, true);
+ spl_autoload_register(array('ComposerAutoloaderInit4ae4005bb4ec82f3372265feb7e84f37', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
- spl_autoload_unregister(array('ComposerAutoloaderInitc269e792cec97d4c278bb968546f51b4', 'loadClassLoader'));
+ spl_autoload_unregister(array('ComposerAutoloaderInit4ae4005bb4ec82f3372265feb7e84f37', 'loadClassLoader'));
$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname($vendorDir));
diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json
index 7ee2680..322247d 100644
--- a/core/vendor/composer/installed.json
+++ b/core/vendor/composer/installed.json
@@ -179,109 +179,18 @@
"homepage": "http://symfony.com"
},
{
- "name": "psr/log",
- "version": "1.0.0",
- "version_normalized": "1.0.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/log",
- "reference": "1.0.0"
- },
- "dist": {
- "type": "zip",
- "url": "https://github.com/php-fig/log/archive/1.0.0.zip",
- "reference": "1.0.0",
- "shasum": ""
- },
- "time": "2012-12-21 11:40:51",
- "type": "library",
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Psr\\Log\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
- }
- ],
- "description": "Common interface for logging libraries",
- "keywords": [
- "log",
- "psr",
- "psr-3"
- ]
- },
- {
- "name": "twig/twig",
- "version": "v1.12.3",
- "version_normalized": "1.12.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/fabpot/Twig.git",
- "reference": "v1.12.3"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.12.3",
- "reference": "v1.12.3",
- "shasum": ""
- },
- "require": {
- "php": ">=5.2.4"
- },
- "time": "2013-04-08 12:40:11",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.12-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Twig_": "lib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Armin Ronacher",
- "email": "armin.ronacher@active-4.com"
- }
- ],
- "description": "Twig, the flexible, fast, and secure template language for PHP",
- "homepage": "http://twig.sensiolabs.org",
- "keywords": [
- "templating"
- ]
- },
- {
- "name": "symfony/debug",
+ "name": "symfony/dependency-injection",
"version": "v2.3.1",
"version_normalized": "2.3.1.0",
- "target-dir": "Symfony/Component/Debug",
+ "target-dir": "Symfony/Component/DependencyInjection",
"source": {
"type": "git",
- "url": "https://github.com/symfony/Debug.git",
+ "url": "https://github.com/symfony/DependencyInjection.git",
"reference": "v2.3.1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Debug/zipball/v2.3.1",
+ "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.3.1",
"reference": "v2.3.1",
"shasum": ""
},
@@ -289,15 +198,15 @@
"php": ">=5.3.3"
},
"require-dev": {
- "symfony/http-foundation": ">=2.1,<3.0",
- "symfony/http-kernel": ">=2.1,<3.0"
+ "symfony/config": ">=2.2,<3.0",
+ "symfony/yaml": ">=2.0,<3.0"
},
"suggest": {
- "symfony/class-loader": "",
- "symfony/http-foundation": "",
- "symfony/http-kernel": ""
+ "symfony/config": "",
+ "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
+ "symfony/yaml": ""
},
- "time": "2013-06-02 11:58:44",
+ "time": "2013-06-05 09:51:05",
"type": "library",
"extra": {
"branch-alias": {
@@ -307,7 +216,7 @@
"installation-source": "dist",
"autoload": {
"psr-0": {
- "Symfony\\Component\\Debug\\": ""
+ "Symfony\\Component\\DependencyInjection\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -324,7 +233,7 @@
"homepage": "http://symfony.com/contributors"
}
],
- "description": "Symfony Debug Component",
+ "description": "Symfony DependencyInjection Component",
"homepage": "http://symfony.com"
},
{
@@ -380,32 +289,25 @@
"homepage": "http://symfony.com"
},
{
- "name": "symfony/event-dispatcher",
- "version": "v2.3.0",
- "version_normalized": "2.3.0.0",
- "target-dir": "Symfony/Component/EventDispatcher",
+ "name": "symfony/serializer",
+ "version": "v2.3.1",
+ "version_normalized": "2.3.1.0",
+ "target-dir": "Symfony/Component/Serializer",
"source": {
"type": "git",
- "url": "https://github.com/symfony/EventDispatcher.git",
- "reference": "v2.3.0-RC1"
+ "url": "https://github.com/symfony/Serializer.git",
+ "reference": "v2.3.1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.0-RC1",
- "reference": "v2.3.0-RC1",
+ "url": "https://api.github.com/repos/symfony/Serializer/zipball/v2.3.1",
+ "reference": "v2.3.1",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
- "require-dev": {
- "symfony/dependency-injection": ">=2.0,<3.0"
- },
- "suggest": {
- "symfony/dependency-injection": "",
- "symfony/http-kernel": ""
- },
- "time": "2013-05-13 14:36:40",
+ "time": "2013-05-10 18:12:13",
"type": "library",
"extra": {
"branch-alias": {
@@ -415,7 +317,7 @@
"installation-source": "dist",
"autoload": {
"psr-0": {
- "Symfony\\Component\\EventDispatcher\\": ""
+ "Symfony\\Component\\Serializer\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -432,52 +334,37 @@
"homepage": "http://symfony.com/contributors"
}
],
- "description": "Symfony EventDispatcher Component",
+ "description": "Symfony Serializer Component",
"homepage": "http://symfony.com"
},
{
- "name": "symfony/http-kernel",
+ "name": "symfony/translation",
"version": "v2.3.0",
"version_normalized": "2.3.0.0",
- "target-dir": "Symfony/Component/HttpKernel",
+ "target-dir": "Symfony/Component/Translation",
"source": {
"type": "git",
- "url": "https://github.com/symfony/HttpKernel.git",
- "reference": "v2.3.0"
+ "url": "https://github.com/symfony/Translation.git",
+ "reference": "v2.3.0-RC1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/v2.3.0",
- "reference": "v2.3.0",
+ "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.0-RC1",
+ "reference": "v2.3.0-RC1",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
- "psr/log": ">=1.0,<2.0",
- "symfony/debug": ">=2.3,<3.0",
- "symfony/event-dispatcher": ">=2.1,<3.0",
- "symfony/http-foundation": ">=2.2,<3.0"
+ "php": ">=5.3.3"
},
"require-dev": {
- "symfony/browser-kit": "2.2.*",
- "symfony/class-loader": ">=2.1,<3.0",
"symfony/config": ">=2.0,<3.0",
- "symfony/console": "2.2.*",
- "symfony/dependency-injection": ">=2.0,<3.0",
- "symfony/finder": ">=2.0,<3.0",
- "symfony/process": ">=2.0,<3.0",
- "symfony/routing": ">=2.2,<3.0",
- "symfony/stopwatch": ">=2.2,<3.0"
+ "symfony/yaml": ">=2.2,<3.0"
},
"suggest": {
- "symfony/browser-kit": "",
- "symfony/class-loader": "",
"symfony/config": "",
- "symfony/console": "",
- "symfony/dependency-injection": "",
- "symfony/finder": ""
+ "symfony/yaml": ""
},
- "time": "2013-06-03 14:13:35",
+ "time": "2013-05-13 14:36:40",
"type": "library",
"extra": {
"branch-alias": {
@@ -487,7 +374,7 @@
"installation-source": "dist",
"autoload": {
"psr-0": {
- "Symfony\\Component\\HttpKernel\\": ""
+ "Symfony\\Component\\Translation\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -504,50 +391,30 @@
"homepage": "http://symfony.com/contributors"
}
],
- "description": "Symfony HttpKernel Component",
+ "description": "Symfony Translation Component",
"homepage": "http://symfony.com"
},
{
- "name": "symfony/routing",
- "version": "v2.3.0",
- "version_normalized": "2.3.0.0",
- "target-dir": "Symfony/Component/Routing",
+ "name": "psr/log",
+ "version": "1.0.0",
+ "version_normalized": "1.0.0.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony/Routing.git",
- "reference": "v2.3.0"
+ "url": "https://github.com/php-fig/log",
+ "reference": "1.0.0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.3.0",
- "reference": "v2.3.0",
+ "url": "https://github.com/php-fig/log/archive/1.0.0.zip",
+ "reference": "1.0.0",
"shasum": ""
},
- "require": {
- "php": ">=5.3.3"
- },
- "require-dev": {
- "doctrine/common": ">=2.2,<3.0",
- "psr/log": ">=1.0,<2.0",
- "symfony/config": ">=2.2,<3.0",
- "symfony/yaml": ">=2.0,<3.0"
- },
- "suggest": {
- "doctrine/common": "",
- "symfony/config": "",
- "symfony/yaml": ""
- },
- "time": "2013-05-20 08:57:26",
+ "time": "2012-12-21 11:40:51",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
"installation-source": "dist",
"autoload": {
"psr-0": {
- "Symfony\\Component\\Routing\\": ""
+ "Psr\\Log\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -556,150 +423,102 @@
],
"authors": [
{
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
}
],
- "description": "Symfony Routing Component",
- "homepage": "http://symfony.com"
+ "description": "Common interface for logging libraries",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ]
},
{
- "name": "symfony-cmf/routing",
- "version": "1.1.0-alpha2",
- "version_normalized": "1.1.0.0-alpha2",
- "target-dir": "Symfony/Cmf/Component/Routing",
+ "name": "twig/twig",
+ "version": "v1.12.3",
+ "version_normalized": "1.12.3.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony-cmf/Routing.git",
- "reference": "1.1.0-alpha2"
+ "url": "https://github.com/fabpot/Twig.git",
+ "reference": "v1.12.3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony-cmf/Routing/zipball/1.1.0-alpha2",
- "reference": "1.1.0-alpha2",
+ "url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.12.3",
+ "reference": "v1.12.3",
"shasum": ""
},
"require": {
- "php": ">=5.3.2",
- "psr/log": ">=1.0,<2.0",
- "symfony/http-kernel": ">=2.2,<2.4-dev",
- "symfony/routing": ">=2.2,<2.4-dev"
- },
- "suggest": {
- "symfony/http-foundation": "ChainRouter/DynamicRouter have optional support for Request instances, several enhancers require a Request instances, >=2.2,<2.3-dev"
+ "php": ">=5.2.4"
},
- "time": "2013-05-28 19:50:20",
+ "time": "2013-04-08 12:40:11",
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1-dev"
+ "dev-master": "1.12-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
- "Symfony\\Cmf\\Component\\Routing": ""
+ "Twig_": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3"
],
"authors": [
{
- "name": "Symfony CMF Community",
- "homepage": "https://github.com/symfony-cmf/Routing/contributors"
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Armin Ronacher",
+ "email": "armin.ronacher@active-4.com"
}
],
- "description": "Extends the Symfony2 routing component for dynamic routes and chaining several routers",
- "homepage": "http://cmf.symfony.com",
+ "description": "Twig, the flexible, fast, and secure template language for PHP",
+ "homepage": "http://twig.sensiolabs.org",
"keywords": [
- "database",
- "routing"
+ "templating"
]
},
{
- "name": "symfony/dependency-injection",
+ "name": "symfony/validator",
"version": "v2.3.1",
"version_normalized": "2.3.1.0",
- "target-dir": "Symfony/Component/DependencyInjection",
+ "target-dir": "Symfony/Component/Validator",
"source": {
"type": "git",
- "url": "https://github.com/symfony/DependencyInjection.git",
+ "url": "https://github.com/symfony/Validator.git",
"reference": "v2.3.1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.3.1",
+ "url": "https://api.github.com/repos/symfony/Validator/zipball/v2.3.1",
"reference": "v2.3.1",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.3",
+ "symfony/translation": ">=2.0,<3.0"
},
"require-dev": {
"symfony/config": ">=2.2,<3.0",
+ "symfony/http-foundation": ">=2.1,<3.0",
+ "symfony/intl": ">=2.3,<3.0",
"symfony/yaml": ">=2.0,<3.0"
},
"suggest": {
+ "doctrine/common": "",
"symfony/config": "",
- "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
+ "symfony/http-foundation": "",
+ "symfony/intl": "",
"symfony/yaml": ""
},
- "time": "2013-06-05 09:51:05",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\DependencyInjection\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "description": "Symfony DependencyInjection Component",
- "homepage": "http://symfony.com"
- },
- {
- "name": "symfony/serializer",
- "version": "v2.3.1",
- "version_normalized": "2.3.1.0",
- "target-dir": "Symfony/Component/Serializer",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/Serializer.git",
- "reference": "v2.3.1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/Serializer/zipball/v2.3.1",
- "reference": "v2.3.1",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "time": "2013-05-10 18:12:13",
+ "time": "2013-06-10 16:23:25",
"type": "library",
"extra": {
"branch-alias": {
@@ -709,7 +528,7 @@
"installation-source": "dist",
"autoload": {
"psr-0": {
- "Symfony\\Component\\Serializer\\": ""
+ "Symfony\\Component\\Validator\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -726,22 +545,22 @@
"homepage": "http://symfony.com/contributors"
}
],
- "description": "Symfony Serializer Component",
+ "description": "Symfony Validator Component",
"homepage": "http://symfony.com"
},
{
- "name": "symfony/translation",
+ "name": "symfony/event-dispatcher",
"version": "v2.3.0",
"version_normalized": "2.3.0.0",
- "target-dir": "Symfony/Component/Translation",
+ "target-dir": "Symfony/Component/EventDispatcher",
"source": {
"type": "git",
- "url": "https://github.com/symfony/Translation.git",
+ "url": "https://github.com/symfony/EventDispatcher.git",
"reference": "v2.3.0-RC1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.0-RC1",
+ "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.0-RC1",
"reference": "v2.3.0-RC1",
"shasum": ""
},
@@ -749,12 +568,11 @@
"php": ">=5.3.3"
},
"require-dev": {
- "symfony/config": ">=2.0,<3.0",
- "symfony/yaml": ">=2.2,<3.0"
+ "symfony/dependency-injection": ">=2.0,<3.0"
},
"suggest": {
- "symfony/config": "",
- "symfony/yaml": ""
+ "symfony/dependency-injection": "",
+ "symfony/http-kernel": ""
},
"time": "2013-05-13 14:36:40",
"type": "library",
@@ -766,70 +584,7 @@
"installation-source": "dist",
"autoload": {
"psr-0": {
- "Symfony\\Component\\Translation\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "description": "Symfony Translation Component",
- "homepage": "http://symfony.com"
- },
- {
- "name": "symfony/validator",
- "version": "v2.3.1",
- "version_normalized": "2.3.1.0",
- "target-dir": "Symfony/Component/Validator",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/Validator.git",
- "reference": "v2.3.1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/Validator/zipball/v2.3.1",
- "reference": "v2.3.1",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3",
- "symfony/translation": ">=2.0,<3.0"
- },
- "require-dev": {
- "symfony/config": ">=2.2,<3.0",
- "symfony/http-foundation": ">=2.1,<3.0",
- "symfony/intl": ">=2.3,<3.0",
- "symfony/yaml": ">=2.0,<3.0"
- },
- "suggest": {
- "doctrine/common": "",
- "symfony/config": "",
- "symfony/http-foundation": "",
- "symfony/intl": "",
- "symfony/yaml": ""
- },
- "time": "2013-06-10 16:23:25",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\Validator\\": ""
+ "Symfony\\Component\\EventDispatcher\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -846,7 +601,7 @@
"homepage": "http://symfony.com/contributors"
}
],
- "description": "Symfony Validator Component",
+ "description": "Symfony EventDispatcher Component",
"homepage": "http://symfony.com"
},
{
@@ -1175,19 +930,264 @@
]
},
{
- "name": "symfony/yaml",
+ "name": "symfony/debug",
+ "version": "v2.3.1",
+ "version_normalized": "2.3.1.0",
+ "target-dir": "Symfony/Component/Debug",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Debug.git",
+ "reference": "v2.3.1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Debug/zipball/v2.3.1",
+ "reference": "v2.3.1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "symfony/http-foundation": ">=2.1,<3.0",
+ "symfony/http-kernel": ">=2.1,<3.0"
+ },
+ "suggest": {
+ "symfony/class-loader": "",
+ "symfony/http-foundation": "",
+ "symfony/http-kernel": ""
+ },
+ "time": "2013-06-02 11:58:44",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Debug\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Debug Component",
+ "homepage": "http://symfony.com"
+ },
+ {
+ "name": "symfony/http-kernel",
"version": "v2.3.0",
"version_normalized": "2.3.0.0",
+ "target-dir": "Symfony/Component/HttpKernel",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/HttpKernel.git",
+ "reference": "v2.3.0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/v2.3.0",
+ "reference": "v2.3.0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "psr/log": ">=1.0,<2.0",
+ "symfony/debug": ">=2.3,<3.0",
+ "symfony/event-dispatcher": ">=2.1,<3.0",
+ "symfony/http-foundation": ">=2.2,<3.0"
+ },
+ "require-dev": {
+ "symfony/browser-kit": "2.2.*",
+ "symfony/class-loader": ">=2.1,<3.0",
+ "symfony/config": ">=2.0,<3.0",
+ "symfony/console": "2.2.*",
+ "symfony/dependency-injection": ">=2.0,<3.0",
+ "symfony/finder": ">=2.0,<3.0",
+ "symfony/process": ">=2.0,<3.0",
+ "symfony/routing": ">=2.2,<3.0",
+ "symfony/stopwatch": ">=2.2,<3.0"
+ },
+ "suggest": {
+ "symfony/browser-kit": "",
+ "symfony/class-loader": "",
+ "symfony/config": "",
+ "symfony/console": "",
+ "symfony/dependency-injection": "",
+ "symfony/finder": ""
+ },
+ "time": "2013-06-03 14:13:35",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\HttpKernel\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony HttpKernel Component",
+ "homepage": "http://symfony.com"
+ },
+ {
+ "name": "symfony/routing",
+ "version": "v2.3.0",
+ "version_normalized": "2.3.0.0",
+ "target-dir": "Symfony/Component/Routing",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Routing.git",
+ "reference": "v2.3.0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.3.0",
+ "reference": "v2.3.0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "doctrine/common": ">=2.2,<3.0",
+ "psr/log": ">=1.0,<2.0",
+ "symfony/config": ">=2.2,<3.0",
+ "symfony/yaml": ">=2.0,<3.0"
+ },
+ "suggest": {
+ "doctrine/common": "",
+ "symfony/config": "",
+ "symfony/yaml": ""
+ },
+ "time": "2013-05-20 08:57:26",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Routing\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Routing Component",
+ "homepage": "http://symfony.com"
+ },
+ {
+ "name": "symfony-cmf/routing",
+ "version": "1.1.0-beta1",
+ "version_normalized": "1.1.0.0-beta1",
+ "target-dir": "Symfony/Cmf/Component/Routing",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony-cmf/Routing.git",
+ "reference": "1.1.0-beta1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony-cmf/Routing/zipball/1.1.0-beta1",
+ "reference": "1.1.0-beta1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "psr/log": ">=1.0,<2.0",
+ "symfony/http-kernel": ">=2.2,<3.0",
+ "symfony/routing": ">=2.2,<3.0"
+ },
+ "suggest": {
+ "symfony/http-foundation": "ChainRouter/DynamicRouter have optional support for Request instances, several enhancers require a Request instances, ~2.2"
+ },
+ "time": "2013-06-03 17:23:01",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Cmf\\Component\\Routing": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Symfony CMF Community",
+ "homepage": "https://github.com/symfony-cmf/Routing/contributors"
+ }
+ ],
+ "description": "Extends the Symfony2 routing component for dynamic routes and chaining several routers",
+ "homepage": "http://cmf.symfony.com",
+ "keywords": [
+ "database",
+ "routing"
+ ]
+ },
+ {
+ "name": "symfony/yaml",
+ "version": "v2.3.1",
+ "version_normalized": "2.3.1.0",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
- "reference": "v2.3.0-RC1"
+ "reference": "v2.3.1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.3.0-RC1",
- "reference": "v2.3.0-RC1",
+ "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.3.1",
+ "reference": "v2.3.1",
"shasum": ""
},
"require": {
@@ -1593,5 +1593,143 @@
"testing",
"xunit"
]
+ },
+ {
+ "name": "zendframework/zend-stdlib",
+ "version": "2.2.1",
+ "version_normalized": "2.2.1.0",
+ "target-dir": "Zend/Stdlib",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zendframework/Component_ZendStdlib.git",
+ "reference": "release-2.2.1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zendframework/Component_ZendStdlib/zipball/release-2.2.1",
+ "reference": "release-2.2.1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "zendframework/zend-eventmanager": "To support aggregate hydrator usage",
+ "zendframework/zend-servicemanager": "To support hydrator plugin manager usage"
+ },
+ "time": "2013-06-12 19:46:58",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.2-dev",
+ "dev-develop": "2.3-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Zend\\Stdlib\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "keywords": [
+ "stdlib",
+ "zf2"
+ ]
+ },
+ {
+ "name": "zendframework/zend-escaper",
+ "version": "2.2.1",
+ "version_normalized": "2.2.1.0",
+ "target-dir": "Zend/Escaper",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zendframework/Component_ZendEscaper.git",
+ "reference": "release-2.2.1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zendframework/Component_ZendEscaper/zipball/release-2.2.1",
+ "reference": "release-2.2.1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "time": "2013-05-01 21:53:03",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.2-dev",
+ "dev-develop": "2.3-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Zend\\Escaper\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "keywords": [
+ "escaper",
+ "zf2"
+ ]
+ },
+ {
+ "name": "zendframework/zend-feed",
+ "version": "2.2.1",
+ "version_normalized": "2.2.1.0",
+ "target-dir": "Zend/Feed",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zendframework/Component_ZendFeed.git",
+ "reference": "release-2.2.1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zendframework/Component_ZendFeed/zipball/release-2.2.1",
+ "reference": "release-2.2.1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "zendframework/zend-escaper": "self.version",
+ "zendframework/zend-stdlib": "self.version"
+ },
+ "suggest": {
+ "zendframework/zend-http": "Zend\\Http for PubSubHubbub, and optionally for use with Zend\\Feed\\Reader",
+ "zendframework/zend-servicemanager": "Zend\\ServiceManager component, for default/recommended ExtensionManager implementations",
+ "zendframework/zend-validator": "Zend\\Validator component"
+ },
+ "time": "2013-06-12 19:45:31",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.2-dev",
+ "dev-develop": "2.3-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Zend\\Feed\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "provides functionality for consuming RSS and Atom feeds",
+ "keywords": [
+ "feed",
+ "zf2"
+ ]
}
]
diff --git a/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/.travis.yml b/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/.travis.yml
index 9c9cce9..494db98 100644
--- a/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/.travis.yml
+++ b/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/.travis.yml
@@ -6,6 +6,7 @@ php:
env:
- SYMFONY_VERSION=2.2.*
+ - SYMFONY_VERSION=2.3.*
- SYMFONY_VERSION=dev-master
before_script:
diff --git a/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/CHANGELOG.md b/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/CHANGELOG.md
index a93a031..fe5dcfc 100644
--- a/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/CHANGELOG.md
+++ b/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/CHANGELOG.md
@@ -1,6 +1,8 @@
-# Changelog
+Changelog
+=========
-## 1.1
+1.1
+---
-* Dropped Symfony 2.1 support and got rid of ConfigurableUrlMatcher class
-* Fix locale handling to always respect locale but never have unnecessary ?locale= \ No newline at end of file
+* **2013-04-30**: Dropped Symfony 2.1 support and got rid of ConfigurableUrlMatcher class
+* **2013-04-05**: [ContentAwareGenerator] Fix locale handling to always respect locale but never have unnecessary ?locale=
diff --git a/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/composer.json b/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/composer.json
index 8559c1a..63cfa9b 100644
--- a/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/composer.json
+++ b/core/vendor/symfony-cmf/routing/Symfony/Cmf/Component/Routing/composer.json
@@ -13,13 +13,13 @@
],
"minimum-stability": "dev",
"require": {
- "php": ">=5.3.2",
- "symfony/routing": ">=2.2,<2.4-dev",
- "symfony/http-kernel": ">=2.2,<2.4-dev",
+ "php": ">=5.3.3",
+ "symfony/routing": "~2.2",
+ "symfony/http-kernel": "~2.2",
"psr/log": "~1.0"
},
"suggest": {
- "symfony/http-foundation": "ChainRouter/DynamicRouter have optional support for Request instances, several enhancers require a Request instances, >=2.2,<2.3-dev"
+ "symfony/http-foundation": "ChainRouter/DynamicRouter have optional support for Request instances, several enhancers require a Request instances, ~2.2"
},
"autoload": {
"psr-0": { "Symfony\\Cmf\\Component\\Routing": "" }
diff --git a/core/vendor/zendframework/zend-escaper/Zend/Escaper/Escaper.php b/core/vendor/zendframework/zend-escaper/Zend/Escaper/Escaper.php
new file mode 100644
index 0000000..38ab113
--- /dev/null
+++ b/core/vendor/zendframework/zend-escaper/Zend/Escaper/Escaper.php
@@ -0,0 +1,390 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Escaper;
+
+use Zend\Escaper\Exception;
+
+/**
+ * Context specific methods for use in secure output escaping
+ */
+class Escaper
+{
+ /**
+ * Entity Map mapping Unicode codepoints to any available named HTML entities.
+ *
+ * While HTML supports far more named entities, the lowest common denominator
+ * has become HTML5's XML Serialisation which is restricted to the those named
+ * entities that XML supports. Using HTML entities would result in this error:
+ * XML Parsing Error: undefined entity
+ *
+ * @var array
+ */
+ protected static $htmlNamedEntityMap = array(
+ 34 => 'quot', // quotation mark
+ 38 => 'amp', // ampersand
+ 60 => 'lt', // less-than sign
+ 62 => 'gt', // greater-than sign
+ );
+
+ /**
+ * Current encoding for escaping. If not UTF-8, we convert strings from this encoding
+ * pre-escaping and back to this encoding post-escaping.
+ *
+ * @var string
+ */
+ protected $encoding = 'utf-8';
+
+ /**
+ * Holds the value of the special flags passed as second parameter to
+ * htmlspecialchars(). We modify these for PHP 5.4 to take advantage
+ * of the new ENT_SUBSTITUTE flag for correctly dealing with invalid
+ * UTF-8 sequences.
+ *
+ * @var string
+ */
+ protected $htmlSpecialCharsFlags = ENT_QUOTES;
+
+ /**
+ * Static Matcher which escapes characters for HTML Attribute contexts
+ *
+ * @var callable
+ */
+ protected $htmlAttrMatcher;
+
+ /**
+ * Static Matcher which escapes characters for Javascript contexts
+ *
+ * @var callable
+ */
+ protected $jsMatcher;
+
+ /**
+ * Static Matcher which escapes characters for CSS Attribute contexts
+ *
+ * @var callable
+ */
+ protected $cssMatcher;
+
+ /**
+ * List of all encoding supported by this class
+ *
+ * @var array
+ */
+ protected $supportedEncodings = array(
+ 'iso-8859-1', 'iso8859-1', 'iso-8859-5', 'iso8859-5',
+ 'iso-8859-15', 'iso8859-15', 'utf-8', 'cp866',
+ 'ibm866', '866', 'cp1251', 'windows-1251',
+ 'win-1251', '1251', 'cp1252', 'windows-1252',
+ '1252', 'koi8-r', 'koi8-ru', 'koi8r',
+ 'big5', '950', 'gb2312', '936',
+ 'big5-hkscs', 'shift_jis', 'sjis', 'sjis-win',
+ 'cp932', '932', 'euc-jp', 'eucjp',
+ 'eucjp-win', 'macroman'
+ );
+
+ /**
+ * Constructor: Single parameter allows setting of global encoding for use by
+ * the current object. If PHP 5.4 is detected, additional ENT_SUBSTITUTE flag
+ * is set for htmlspecialchars() calls.
+ *
+ * @param string $encoding
+ * @throws Exception\InvalidArgumentException
+ */
+ public function __construct($encoding = null)
+ {
+ if ($encoding !== null) {
+ $encoding = (string) $encoding;
+ if ($encoding === '') {
+ throw new Exception\InvalidArgumentException(
+ get_class($this) . ' constructor parameter does not allow a blank value'
+ );
+ }
+
+ $encoding = strtolower($encoding);
+ if (!in_array($encoding, $this->supportedEncodings)) {
+ throw new Exception\InvalidArgumentException(
+ 'Value of \'' . $encoding . '\' passed to ' . get_class($this)
+ . ' constructor parameter is invalid. Provide an encoding supported by htmlspecialchars()'
+ );
+ }
+
+ $this->encoding = $encoding;
+ }
+
+ if (defined('ENT_SUBSTITUTE')) {
+ $this->htmlSpecialCharsFlags|= ENT_SUBSTITUTE;
+ }
+
+ // set matcher callbacks
+ $this->htmlAttrMatcher = array($this, 'htmlAttrMatcher');
+ $this->jsMatcher = array($this, 'jsMatcher');
+ $this->cssMatcher = array($this, 'cssMatcher');
+ }
+
+ /**
+ * Return the encoding that all output/input is expected to be encoded in.
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ return $this->encoding;
+ }
+
+ /**
+ * Escape a string for the HTML Body context where there are very few characters
+ * of special meaning. Internally this will use htmlspecialchars().
+ *
+ * @param string $string
+ * @return string
+ */
+ public function escapeHtml($string)
+ {
+ $result = htmlspecialchars($string, $this->htmlSpecialCharsFlags, $this->encoding);
+ return $result;
+ }
+
+ /**
+ * Escape a string for the HTML Attribute context. We use an extended set of characters
+ * to escape that are not covered by htmlspecialchars() to cover cases where an attribute
+ * might be unquoted or quoted illegally (e.g. backticks are valid quotes for IE).
+ *
+ * @param string $string
+ * @return string
+ */
+ public function escapeHtmlAttr($string)
+ {
+ $string = $this->toUtf8($string);
+ if ($string === '' || ctype_digit($string)) {
+ return $string;
+ }
+
+ $result = preg_replace_callback('/[^a-z0-9,\.\-_]/iSu', $this->htmlAttrMatcher, $string);
+ return $this->fromUtf8($result);
+ }
+
+ /**
+ * Escape a string for the Javascript context. This does not use json_encode(). An extended
+ * set of characters are escaped beyond ECMAScript's rules for Javascript literal string
+ * escaping in order to prevent misinterpretation of Javascript as HTML leading to the
+ * injection of special characters and entities. The escaping used should be tolerant
+ * of cases where HTML escaping was not applied on top of Javascript escaping correctly.
+ * Backslash escaping is not used as it still leaves the escaped character as-is and so
+ * is not useful in a HTML context.
+ *
+ * @param string $string
+ * @return string
+ */
+ public function escapeJs($string)
+ {
+ $string = $this->toUtf8($string);
+ if ($string === '' || ctype_digit($string)) {
+ return $string;
+ }
+
+ $result = preg_replace_callback('/[^a-z0-9,\._]/iSu', $this->jsMatcher, $string);
+ return $this->fromUtf8($result);
+ }
+
+ /**
+ * Escape a string for the URI or Parameter contexts. This should not be used to escape
+ * an entire URI - only a subcomponent being inserted. The function is a simple proxy
+ * to rawurlencode() which now implements RFC 3986 since PHP 5.3 completely.
+ *
+ * @param string $string
+ * @return string
+ */
+ public function escapeUrl($string)
+ {
+ return rawurlencode($string);
+ }
+
+ /**
+ * Escape a string for the CSS context. CSS escaping can be applied to any string being
+ * inserted into CSS and escapes everything except alphanumerics.
+ *
+ * @param string $string
+ * @return string
+ */
+ public function escapeCss($string)
+ {
+ $string = $this->toUtf8($string);
+ if ($string === '' || ctype_digit($string)) {
+ return $string;
+ }
+
+ $result = preg_replace_callback('/[^a-z0-9]/iSu', $this->cssMatcher, $string);
+ return $this->fromUtf8($result);
+ }
+
+ /**
+ * Callback function for preg_replace_callback that applies HTML Attribute
+ * escaping to all matches.
+ *
+ * @param array $matches
+ * @return string
+ */
+ protected function htmlAttrMatcher($matches)
+ {
+ $chr = $matches[0];
+ $ord = ord($chr);
+
+ /**
+ * The following replaces characters undefined in HTML with the
+ * hex entity for the Unicode replacement character.
+ */
+ if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r")
+ || ($ord >= 0x7f && $ord <= 0x9f)
+ ) {
+ return '&#xFFFD;';
+ }
+
+ /**
+ * Check if the current character to escape has a name entity we should
+ * replace it with while grabbing the integer value of the character.
+ */
+ if (strlen($chr) > 1) {
+ $chr = $this->convertEncoding($chr, 'UTF-16BE', 'UTF-8');
+ }
+
+ $hex = bin2hex($chr);
+ $ord = hexdec($hex);
+ if (isset(static::$htmlNamedEntityMap[$ord])) {
+ return '&' . static::$htmlNamedEntityMap[$ord] . ';';
+ }
+
+ /**
+ * Per OWASP recommendations, we'll use upper hex entities
+ * for any other characters where a named entity does not exist.
+ */
+ if ($ord > 255) {
+ return sprintf('&#x%04X;', $ord);
+ }
+ return sprintf('&#x%02X;', $ord);
+ }
+
+ /**
+ * Callback function for preg_replace_callback that applies Javascript
+ * escaping to all matches.
+ *
+ * @param array $matches
+ * @return string
+ */
+ protected function jsMatcher($matches)
+ {
+ $chr = $matches[0];
+ if (strlen($chr) == 1) {
+ return sprintf('\\x%02X', ord($chr));
+ }
+ $chr = $this->convertEncoding($chr, 'UTF-16BE', 'UTF-8');
+ return sprintf('\\u%04s', strtoupper(bin2hex($chr)));
+ }
+
+ /**
+ * Callback function for preg_replace_callback that applies CSS
+ * escaping to all matches.
+ *
+ * @param array $matches
+ * @return string
+ */
+ protected function cssMatcher($matches)
+ {
+ $chr = $matches[0];
+ if (strlen($chr) == 1) {
+ $ord = ord($chr);
+ } else {
+ $chr = $this->convertEncoding($chr, 'UTF-16BE', 'UTF-8');
+ $ord = hexdec(bin2hex($chr));
+ }
+ return sprintf('\\%X ', $ord);
+ }
+
+ /**
+ * Converts a string to UTF-8 from the base encoding. The base encoding is set via this
+ * class' constructor.
+ *
+ * @param string $string
+ * @throws Exception\RuntimeException
+ * @return string
+ */
+ protected function toUtf8($string)
+ {
+ if ($this->getEncoding() === 'utf-8') {
+ $result = $string;
+ } else {
+ $result = $this->convertEncoding($string, 'UTF-8', $this->getEncoding());
+ }
+
+ if (!$this->isUtf8($result)) {
+ throw new Exception\RuntimeException(sprintf(
+ 'String to be escaped was not valid UTF-8 or could not be converted: %s', $result
+ ));
+ }
+
+ return $result;
+ }
+
+ /**
+ * Converts a string from UTF-8 to the base encoding. The base encoding is set via this
+ * class' constructor.
+ * @param string $string
+ * @return string
+ */
+ protected function fromUtf8($string)
+ {
+ if ($this->getEncoding() === 'utf-8') {
+ return $string;
+ }
+
+ return $this->convertEncoding($string, $this->getEncoding(), 'UTF-8');
+ }
+
+ /**
+ * Checks if a given string appears to be valid UTF-8 or not.
+ *
+ * @param string $string
+ * @return bool
+ */
+ protected function isUtf8($string)
+ {
+ return ($string === '' || preg_match('/^./su', $string));
+ }
+
+ /**
+ * Encoding conversion helper which wraps iconv and mbstring where they exist or throws
+ * and exception where neither is available.
+ *
+ * @param string $string
+ * @param string $to
+ * @param array|string $from
+ * @throws Exception\RuntimeException
+ * @return string
+ */
+ protected function convertEncoding($string, $to, $from)
+ {
+ $result = '';
+ if (function_exists('iconv')) {
+ $result = iconv($from, $to, $string);
+ } elseif (function_exists('mb_convert_encoding')) {
+ $result = mb_convert_encoding($string, $to, $from);
+ } else {
+ throw new Exception\RuntimeException(
+ get_class($this)
+ . ' requires either the iconv or mbstring extension to be installed'
+ . ' when escaping for non UTF-8 strings.'
+ );
+ }
+
+ if ($result === false) {
+ return ''; // return non-fatal blank string on encoding errors from users
+ }
+ return $result;
+ }
+}
diff --git a/core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/ExceptionInterface.php b/core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/ExceptionInterface.php
new file mode 100644
index 0000000..364dd67
--- /dev/null
+++ b/core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/ExceptionInterface.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Escaper\Exception;
+
+interface ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/InvalidArgumentException.php b/core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000..78c4da7
--- /dev/null
+++ b/core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/InvalidArgumentException.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Escaper\Exception;
+
+/**
+ * Invalid argument exception
+ */
+class InvalidArgumentException extends \InvalidArgumentException implements
+ ExceptionInterface
+{
+}
diff --git a/core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/RuntimeException.php b/core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/RuntimeException.php
new file mode 100644
index 0000000..dec2501
--- /dev/null
+++ b/core/vendor/zendframework/zend-escaper/Zend/Escaper/Exception/RuntimeException.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Escaper\Exception;
+
+/**
+ * Invalid argument exception
+ */
+class RuntimeException extends \RuntimeException implements
+ ExceptionInterface
+{
+}
diff --git a/core/vendor/zendframework/zend-escaper/Zend/Escaper/README.md b/core/vendor/zendframework/zend-escaper/Zend/Escaper/README.md
new file mode 100644
index 0000000..83bd916
--- /dev/null
+++ b/core/vendor/zendframework/zend-escaper/Zend/Escaper/README.md
@@ -0,0 +1,15 @@
+Escaper Component from ZF2
+==========================
+
+This is the Escaper component for ZF2.
+
+- File issues at https://github.com/zendframework/zf2/issues
+- Create pull requests against https://github.com/zendframework/zf2
+- Documentation is at http://framework.zend.com/docs
+
+LICENSE
+-------
+
+The files in this archive are released under the [Zend Framework
+license](http://framework.zend.com/license), which is a 3-clause BSD license.
+
diff --git a/core/vendor/zendframework/zend-escaper/Zend/Escaper/composer.json b/core/vendor/zendframework/zend-escaper/Zend/Escaper/composer.json
new file mode 100644
index 0000000..3b2f2b6
--- /dev/null
+++ b/core/vendor/zendframework/zend-escaper/Zend/Escaper/composer.json
@@ -0,0 +1,24 @@
+{
+ "name": "zendframework/zend-escaper",
+ "description": " ",
+ "license": "BSD-3-Clause",
+ "keywords": [
+ "zf2",
+ "escaper"
+ ],
+ "autoload": {
+ "psr-0": {
+ "Zend\\Escaper\\": ""
+ }
+ },
+ "target-dir": "Zend/Escaper",
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.2-dev",
+ "dev-develop": "2.3-dev"
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/BadMethodCallException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/BadMethodCallException.php
new file mode 100644
index 0000000..34ab718
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/BadMethodCallException.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Exception;
+
+class BadMethodCallException
+ extends \BadMethodCallException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/ExceptionInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/ExceptionInterface.php
new file mode 100644
index 0000000..f4cf0a0
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/ExceptionInterface.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Exception;
+
+interface ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/InvalidArgumentException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000..09930c9
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/InvalidArgumentException.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Exception;
+
+class InvalidArgumentException
+ extends \InvalidArgumentException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/RuntimeException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/RuntimeException.php
new file mode 100644
index 0000000..27a32c6
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Exception/RuntimeException.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Exception;
+
+class RuntimeException
+ extends \RuntimeException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/AbstractCallback.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/AbstractCallback.php
new file mode 100644
index 0000000..b3ab190
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/AbstractCallback.php
@@ -0,0 +1,291 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub;
+
+use Traversable;
+use Zend\Http\PhpEnvironment\Response as PhpResponse;
+use Zend\Stdlib\ArrayUtils;
+
+abstract class AbstractCallback implements CallbackInterface
+{
+ /**
+ * An instance of Zend\Feed\Pubsubhubbub\Model\SubscriptionPersistenceInterface
+ * used to background save any verification tokens associated with a subscription
+ * or other.
+ *
+ * @var Model\SubscriptionPersistenceInterface
+ */
+ protected $storage = null;
+
+ /**
+ * An instance of a class handling Http Responses. This is implemented in
+ * Zend\Feed\Pubsubhubbub\HttpResponse which shares an unenforced interface with
+ * (i.e. not inherited from) Zend\Controller\Response\Http.
+ *
+ * @var HttpResponse|PhpResponse
+ */
+ protected $httpResponse = null;
+
+ /**
+ * The number of Subscribers for which any updates are on behalf of.
+ *
+ * @var int
+ */
+ protected $subscriberCount = 1;
+
+ /**
+ * Constructor; accepts an array or Traversable object to preset
+ * options for the Subscriber without calling all supported setter
+ * methods in turn.
+ *
+ * @param array|Traversable $options Options array or Traversable object
+ */
+ public function __construct($options = null)
+ {
+ if ($options !== null) {
+ $this->setOptions($options);
+ }
+ }
+
+ /**
+ * Process any injected configuration options
+ *
+ * @param array|Traversable $options Options array or Traversable object
+ * @return AbstractCallback
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setOptions($options)
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ }
+
+ if (!is_array($options)) {
+ throw new Exception\InvalidArgumentException('Array or Traversable object'
+ . 'expected, got ' . gettype($options));
+ }
+
+ if (is_array($options)) {
+ $this->setOptions($options);
+ }
+
+ if (array_key_exists('storage', $options)) {
+ $this->setStorage($options['storage']);
+ }
+ return $this;
+ }
+
+ /**
+ * Send the response, including all headers.
+ * If you wish to handle this via Zend\Http, use the getter methods
+ * to retrieve any data needed to be set on your HTTP Response object, or
+ * simply give this object the HTTP Response instance to work with for you!
+ *
+ * @return void
+ */
+ public function sendResponse()
+ {
+ $this->getHttpResponse()->send();
+ }
+
+ /**
+ * Sets an instance of Zend\Feed\Pubsubhubbub\Model\SubscriptionPersistence used
+ * to background save any verification tokens associated with a subscription
+ * or other.
+ *
+ * @param Model\SubscriptionPersistenceInterface $storage
+ * @return AbstractCallback
+ */
+ public function setStorage(Model\SubscriptionPersistenceInterface $storage)
+ {
+ $this->storage = $storage;
+ return $this;
+ }
+
+ /**
+ * Gets an instance of Zend\Feed\Pubsubhubbub\Model\SubscriptionPersistence used
+ * to background save any verification tokens associated with a subscription
+ * or other.
+ *
+ * @return Model\SubscriptionPersistenceInterface
+ * @throws Exception\RuntimeException
+ */
+ public function getStorage()
+ {
+ if ($this->storage === null) {
+ throw new Exception\RuntimeException('No storage object has been'
+ . ' set that subclasses Zend\Feed\Pubsubhubbub\Model\SubscriptionPersistence');
+ }
+ return $this->storage;
+ }
+
+ /**
+ * An instance of a class handling Http Responses. This is implemented in
+ * Zend\Feed\Pubsubhubbub\HttpResponse which shares an unenforced interface with
+ * (i.e. not inherited from) Zend\Controller\Response\Http.
+ *
+ * @param HttpResponse|PhpResponse $httpResponse
+ * @return AbstractCallback
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setHttpResponse($httpResponse)
+ {
+ if (!$httpResponse instanceof HttpResponse && !$httpResponse instanceof PhpResponse) {
+ throw new Exception\InvalidArgumentException('HTTP Response object must'
+ . ' implement one of Zend\Feed\Pubsubhubbub\HttpResponse or'
+ . ' Zend\Http\PhpEnvironment\Response');
+ }
+ $this->httpResponse = $httpResponse;
+ return $this;
+ }
+
+ /**
+ * An instance of a class handling Http Responses. This is implemented in
+ * Zend\Feed\Pubsubhubbub\HttpResponse which shares an unenforced interface with
+ * (i.e. not inherited from) Zend\Controller\Response\Http.
+ *
+ * @return HttpResponse|PhpResponse
+ */
+ public function getHttpResponse()
+ {
+ if ($this->httpResponse === null) {
+ $this->httpResponse = new HttpResponse;
+ }
+ return $this->httpResponse;
+ }
+
+ /**
+ * Sets the number of Subscribers for which any updates are on behalf of.
+ * In other words, is this class serving one or more subscribers? How many?
+ * Defaults to 1 if left unchanged.
+ *
+ * @param string|int $count
+ * @return AbstractCallback
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setSubscriberCount($count)
+ {
+ $count = intval($count);
+ if ($count <= 0) {
+ throw new Exception\InvalidArgumentException('Subscriber count must be'
+ . ' greater than zero');
+ }
+ $this->subscriberCount = $count;
+ return $this;
+ }
+
+ /**
+ * Gets the number of Subscribers for which any updates are on behalf of.
+ * In other words, is this class serving one or more subscribers? How many?
+ *
+ * @return int
+ */
+ public function getSubscriberCount()
+ {
+ return $this->subscriberCount;
+ }
+
+ /**
+ * Attempt to detect the callback URL (specifically the path forward)
+ * @return string
+ */
+ protected function _detectCallbackUrl()
+ {
+ $callbackUrl = '';
+ if (isset($_SERVER['HTTP_X_ORIGINAL_URL'])) {
+ $callbackUrl = $_SERVER['HTTP_X_ORIGINAL_URL'];
+ } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
+ $callbackUrl = $_SERVER['HTTP_X_REWRITE_URL'];
+ } elseif (isset($_SERVER['REQUEST_URI'])) {
+ $callbackUrl = $_SERVER['REQUEST_URI'];
+ $scheme = 'http';
+ if ($_SERVER['HTTPS'] == 'on') {
+ $scheme = 'https';
+ }
+ $schemeAndHttpHost = $scheme . '://' . $this->_getHttpHost();
+ if (strpos($callbackUrl, $schemeAndHttpHost) === 0) {
+ $callbackUrl = substr($callbackUrl, strlen($schemeAndHttpHost));
+ }
+ } elseif (isset($_SERVER['ORIG_PATH_INFO'])) {
+ $callbackUrl= $_SERVER['ORIG_PATH_INFO'];
+ if (!empty($_SERVER['QUERY_STRING'])) {
+ $callbackUrl .= '?' . $_SERVER['QUERY_STRING'];
+ }
+ }
+ return $callbackUrl;
+ }
+
+ /**
+ * Get the HTTP host
+ *
+ * @return string
+ */
+ protected function _getHttpHost()
+ {
+ if (!empty($_SERVER['HTTP_HOST'])) {
+ return $_SERVER['HTTP_HOST'];
+ }
+ $scheme = 'http';
+ if ($_SERVER['HTTPS'] == 'on') {
+ $scheme = 'https';
+ }
+ $name = $_SERVER['SERVER_NAME'];
+ $port = $_SERVER['SERVER_PORT'];
+ if (($scheme == 'http' && $port == 80)
+ || ($scheme == 'https' && $port == 443)
+ ) {
+ return $name;
+ }
+
+ return $name . ':' . $port;
+ }
+
+ /**
+ * Retrieve a Header value from either $_SERVER or Apache
+ *
+ * @param string $header
+ * @return bool|string
+ */
+ protected function _getHeader($header)
+ {
+ $temp = strtoupper(str_replace('-', '_', $header));
+ if (!empty($_SERVER[$temp])) {
+ return $_SERVER[$temp];
+ }
+ $temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
+ if (!empty($_SERVER[$temp])) {
+ return $_SERVER[$temp];
+ }
+ if (function_exists('apache_request_headers')) {
+ $headers = apache_request_headers();
+ if (!empty($headers[$header])) {
+ return $headers[$header];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return the raw body of the request
+ *
+ * @return string|false Raw body, or false if not present
+ */
+ protected function _getRawBody()
+ {
+ $body = file_get_contents('php://input');
+ if (strlen(trim($body)) == 0 && isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
+ $body = $GLOBALS['HTTP_RAW_POST_DATA'];
+ }
+ if (strlen(trim($body)) > 0) {
+ return $body;
+ }
+ return false;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/CallbackInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/CallbackInterface.php
new file mode 100644
index 0000000..9bcc6e2
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/CallbackInterface.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub;
+
+interface CallbackInterface
+{
+ /**
+ * Handle any callback from a Hub Server responding to a subscription or
+ * unsubscription request. This should be the Hub Server confirming the
+ * the request prior to taking action on it.
+ *
+ * @param array $httpData GET/POST data if available and not in $_GET/POST
+ * @param bool $sendResponseNow Whether to send response now or when asked
+ */
+ public function handle(array $httpData = null, $sendResponseNow = false);
+
+ /**
+ * Send the response, including all headers.
+ * If you wish to handle this via Controller, use the getter methods
+ * to retrieve any data needed to be set on your HTTP Response object, or
+ * simply give this object the HTTP Response instance to work with for you!
+ *
+ * @return void
+ */
+ public function sendResponse();
+
+ /**
+ * An instance of a class handling Http Responses. This is implemented in
+ * Zend\Feed\Pubsubhubbub\HttpResponse which shares an unenforced interface with
+ * (i.e. not inherited from) Zend\Feed\Pubsubhubbub\AbstractCallback.
+ *
+ * @param HttpResponse|\Zend\Http\PhpEnvironment\Response $httpResponse
+ */
+ public function setHttpResponse($httpResponse);
+
+ /**
+ * An instance of a class handling Http Responses. This is implemented in
+ * Zend\Feed\Pubsubhubbub\HttpResponse which shares an unenforced interface with
+ * (i.e. not inherited from) Zend\Feed\Pubsubhubbub\AbstractCallback.
+ *
+ * @return HttpResponse|\Zend\Http\PhpEnvironment\Response
+ */
+ public function getHttpResponse();
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/ExceptionInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/ExceptionInterface.php
new file mode 100644
index 0000000..75d710c
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/ExceptionInterface.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub\Exception;
+
+use Zend\Feed\Exception\ExceptionInterface as Exception;
+
+interface ExceptionInterface extends Exception
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/InvalidArgumentException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000..0b2339f
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/InvalidArgumentException.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub\Exception;
+
+use Zend\Feed\Exception;
+
+class InvalidArgumentException
+ extends Exception\InvalidArgumentException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/RuntimeException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/RuntimeException.php
new file mode 100644
index 0000000..23e1544
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Exception/RuntimeException.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub\Exception;
+
+use Zend\Feed\Exception;
+
+class RuntimeException
+ extends Exception\RuntimeException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/HttpResponse.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/HttpResponse.php
new file mode 100644
index 0000000..d820cf9
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/HttpResponse.php
@@ -0,0 +1,211 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub;
+
+class HttpResponse
+{
+ /**
+ * The body of any response to the current callback request
+ *
+ * @var string
+ */
+ protected $content = '';
+
+ /**
+ * Array of headers. Each header is an array with keys 'name' and 'value'
+ *
+ * @var array
+ */
+ protected $headers = array();
+
+ /**
+ * HTTP response code to use in headers
+ *
+ * @var int
+ */
+ protected $statusCode = 200;
+
+ /**
+ * Send the response, including all headers
+ *
+ * @return void
+ */
+ public function send()
+ {
+ $this->sendHeaders();
+ echo $this->getContent();
+ }
+
+ /**
+ * Send all headers
+ *
+ * Sends any headers specified. If an {@link setHttpResponseCode() HTTP response code}
+ * has been specified, it is sent with the first header.
+ *
+ * @return void
+ */
+ public function sendHeaders()
+ {
+ if (count($this->headers) || (200 != $this->statusCode)) {
+ $this->canSendHeaders(true);
+ } elseif (200 == $this->statusCode) {
+ return;
+ }
+ $httpCodeSent = false;
+ foreach ($this->headers as $header) {
+ if (!$httpCodeSent && $this->statusCode) {
+ header($header['name'] . ': ' . $header['value'], $header['replace'], $this->statusCode);
+ $httpCodeSent = true;
+ } else {
+ header($header['name'] . ': ' . $header['value'], $header['replace']);
+ }
+ }
+ if (!$httpCodeSent) {
+ header('HTTP/1.1 ' . $this->statusCode);
+ }
+ }
+
+ /**
+ * Set a header
+ *
+ * If $replace is true, replaces any headers already defined with that
+ * $name.
+ *
+ * @param string $name
+ * @param string $value
+ * @param bool $replace
+ * @return \Zend\Feed\PubSubHubbub\HttpResponse
+ */
+ public function setHeader($name, $value, $replace = false)
+ {
+ $name = $this->_normalizeHeader($name);
+ $value = (string) $value;
+ if ($replace) {
+ foreach ($this->headers as $key => $header) {
+ if ($name == $header['name']) {
+ unset($this->headers[$key]);
+ }
+ }
+ }
+ $this->headers[] = array(
+ 'name' => $name,
+ 'value' => $value,
+ 'replace' => $replace,
+ );
+
+ return $this;
+ }
+
+ /**
+ * Check if a specific Header is set and return its value
+ *
+ * @param string $name
+ * @return string|null
+ */
+ public function getHeader($name)
+ {
+ $name = $this->_normalizeHeader($name);
+ foreach ($this->headers as $header) {
+ if ($header['name'] == $name) {
+ return $header['value'];
+ }
+ }
+ }
+
+ /**
+ * Return array of headers; see {@link $headers} for format
+ *
+ * @return array
+ */
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ /**
+ * Can we send headers?
+ *
+ * @param bool $throw Whether or not to throw an exception if headers have been sent; defaults to false
+ * @return HttpResponse
+ * @throws Exception\RuntimeException
+ */
+ public function canSendHeaders($throw = false)
+ {
+ $ok = headers_sent($file, $line);
+ if ($ok && $throw) {
+ throw new Exception\RuntimeException('Cannot send headers; headers already sent in ' . $file . ', line ' . $line);
+ }
+ return !$ok;
+ }
+
+ /**
+ * Set HTTP response code to use with headers
+ *
+ * @param int $code
+ * @return HttpResponse
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setStatusCode($code)
+ {
+ if (!is_int($code) || (100 > $code) || (599 < $code)) {
+ throw new Exception\InvalidArgumentException('Invalid HTTP response'
+ . ' code:' . $code);
+ }
+ $this->statusCode = $code;
+ return $this;
+ }
+
+ /**
+ * Retrieve HTTP response code
+ *
+ * @return int
+ */
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ /**
+ * Set body content
+ *
+ * @param string $content
+ * @return \Zend\Feed\PubSubHubbub\HttpResponse
+ */
+ public function setContent($content)
+ {
+ $this->content = (string) $content;
+ $this->setHeader('content-length', strlen($content));
+ return $this;
+ }
+
+ /**
+ * Return the body content
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ return $this->content;
+ }
+
+ /**
+ * Normalizes a header name to X-Capitalized-Names
+ *
+ * @param string $name
+ * @return string
+ */
+ protected function _normalizeHeader($name)
+ {
+ $filtered = str_replace(array('-', '_'), ' ', (string) $name);
+ $filtered = ucwords(strtolower($filtered));
+ $filtered = str_replace(' ', '-', $filtered);
+ return $filtered;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/AbstractModel.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/AbstractModel.php
new file mode 100644
index 0000000..023fe8e
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/AbstractModel.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub\Model;
+
+use Zend\Db\TableGateway\TableGateway;
+use Zend\Db\TableGateway\TableGatewayInterface;
+
+class AbstractModel
+{
+ /**
+ * Zend\Db\TableGateway\TableGatewayInterface instance to host database methods
+ *
+ * @var TableGatewayInterface
+ */
+ protected $db = null;
+
+ /**
+ * Constructor
+ *
+ * @param null|TableGatewayInterface $tableGateway
+ */
+ public function __construct(TableGatewayInterface $tableGateway = null)
+ {
+ if ($tableGateway === null) {
+ $parts = explode('\\', get_class($this));
+ $table = strtolower(array_pop($parts));
+ $this->db = new TableGateway($table, null);
+ } else {
+ $this->db = $tableGateway;
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/Subscription.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/Subscription.php
new file mode 100644
index 0000000..a7a4596
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/Subscription.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub\Model;
+
+use DateInterval;
+use DateTime;
+use Zend\Feed\PubSubHubbub;
+
+class Subscription extends AbstractModel implements SubscriptionPersistenceInterface
+{
+ /**
+ * Common DateTime object to assist with unit testing
+ *
+ * @var DateTime
+ */
+ protected $now;
+
+ /**
+ * Save subscription to RDMBS
+ *
+ * @param array $data
+ * @return bool
+ * @throws PubSubHubbub\Exception\InvalidArgumentException
+ */
+ public function setSubscription(array $data)
+ {
+ if (!isset($data['id'])) {
+ throw new PubSubHubbub\Exception\InvalidArgumentException(
+ 'ID must be set before attempting a save'
+ );
+ }
+ $result = $this->db->select(array('id' => $data['id']));
+ if ($result && (0 < count($result))) {
+ $data['created_time'] = $result->current()->created_time;
+ $now = $this->getNow();
+ if (array_key_exists('lease_seconds', $data)
+ && $data['lease_seconds']
+ ) {
+ $data['expiration_time'] = $now->add(new DateInterval('PT' . $data['lease_seconds'] . 'S'))
+ ->format('Y-m-d H:i:s');
+ }
+ $this->db->update(
+ $data,
+ array('id' => $data['id'])
+ );
+ return false;
+ }
+
+ $this->db->insert($data);
+ return true;
+ }
+
+ /**
+ * Get subscription by ID/key
+ *
+ * @param string $key
+ * @return array
+ * @throws PubSubHubbub\Exception\InvalidArgumentException
+ */
+ public function getSubscription($key)
+ {
+ if (empty($key) || !is_string($key)) {
+ throw new PubSubHubbub\Exception\InvalidArgumentException('Invalid parameter "key"'
+ .' of "' . $key . '" must be a non-empty string');
+ }
+ $result = $this->db->select(array('id' => $key));
+ if (count($result)) {
+ return $result->current()->getArrayCopy();
+ }
+ return false;
+ }
+
+ /**
+ * Determine if a subscription matching the key exists
+ *
+ * @param string $key
+ * @return bool
+ * @throws PubSubHubbub\Exception\InvalidArgumentException
+ */
+ public function hasSubscription($key)
+ {
+ if (empty($key) || !is_string($key)) {
+ throw new PubSubHubbub\Exception\InvalidArgumentException('Invalid parameter "key"'
+ .' of "' . $key . '" must be a non-empty string');
+ }
+ $result = $this->db->select(array('id' => $key));
+ if (count($result)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Delete a subscription
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function deleteSubscription($key)
+ {
+ $result = $this->db->select(array('id' => $key));
+ if (count($result)) {
+ $this->db->delete(
+ array('id' => $key)
+ );
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get a new DateTime or the one injected for testing
+ *
+ * @return DateTime
+ */
+ public function getNow()
+ {
+ if (null === $this->now) {
+ return new DateTime();
+ }
+ return $this->now;
+ }
+
+ /**
+ * Set a DateTime instance for assisting with unit testing
+ *
+ * @param DateTime $now
+ * @return Subscription
+ */
+ public function setNow(DateTime $now)
+ {
+ $this->now = $now;
+ return $this;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/SubscriptionPersistenceInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/SubscriptionPersistenceInterface.php
new file mode 100644
index 0000000..717591b
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Model/SubscriptionPersistenceInterface.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub\Model;
+
+interface SubscriptionPersistenceInterface
+{
+
+ /**
+ * Save subscription to RDMBS
+ *
+ * @param array $data The key must be stored here as a $data['id'] entry
+ * @return bool
+ */
+ public function setSubscription(array $data);
+
+ /**
+ * Get subscription by ID/key
+ *
+ * @param string $key
+ * @return array
+ */
+ public function getSubscription($key);
+
+ /**
+ * Determine if a subscription matching the key exists
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function hasSubscription($key);
+
+ /**
+ * Delete a subscription
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function deleteSubscription($key);
+
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/PubSubHubbub.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/PubSubHubbub.php
new file mode 100644
index 0000000..ee00980
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/PubSubHubbub.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub;
+
+use Zend\Escaper\Escaper;
+use Zend\Feed\Reader;
+use Zend\Http;
+
+class PubSubHubbub
+{
+ /**
+ * Verification Modes
+ */
+ const VERIFICATION_MODE_SYNC = 'sync';
+ const VERIFICATION_MODE_ASYNC = 'async';
+
+ /**
+ * Subscription States
+ */
+ const SUBSCRIPTION_VERIFIED = 'verified';
+ const SUBSCRIPTION_NOTVERIFIED = 'not_verified';
+ const SUBSCRIPTION_TODELETE = 'to_delete';
+
+ /**
+ * @var Escaper
+ */
+ protected static $escaper;
+
+ /**
+ * Singleton instance if required of the HTTP client
+ *
+ * @var Http\Client
+ */
+ protected static $httpClient = null;
+
+ /**
+ * Simple utility function which imports any feed URL and
+ * determines the existence of Hub Server endpoints. This works
+ * best if directly given an instance of Zend\Feed\Reader\Atom|Rss
+ * to leverage off.
+ *
+ * @param \Zend\Feed\Reader\Feed\AbstractFeed|string $source
+ * @return array
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function detectHubs($source)
+ {
+ if (is_string($source)) {
+ $feed = Reader\Reader::import($source);
+ } elseif ($source instanceof Reader\Feed\AbstractFeed) {
+ $feed = $source;
+ } else {
+ throw new Exception\InvalidArgumentException('The source parameter was'
+ . ' invalid, i.e. not a URL string or an instance of type'
+ . ' Zend\Feed\Reader\Feed\AbstractFeed');
+ }
+ return $feed->getHubs();
+ }
+
+ /**
+ * Allows the external environment to make Oauth use a specific
+ * Client instance.
+ *
+ * @param Http\Client $httpClient
+ * @return void
+ */
+ public static function setHttpClient(Http\Client $httpClient)
+ {
+ static::$httpClient = $httpClient;
+ }
+
+ /**
+ * Return the singleton instance of the HTTP Client. Note that
+ * the instance is reset and cleared of previous parameters GET/POST.
+ * Headers are NOT reset but handled by this component if applicable.
+ *
+ * @return Http\Client
+ */
+ public static function getHttpClient()
+ {
+ if (!isset(static::$httpClient)) {
+ static::$httpClient = new Http\Client;
+ } else {
+ static::$httpClient->resetParameters();
+ }
+ return static::$httpClient;
+ }
+
+ /**
+ * Simple mechanism to delete the entire singleton HTTP Client instance
+ * which forces an new instantiation for subsequent requests.
+ *
+ * @return void
+ */
+ public static function clearHttpClient()
+ {
+ static::$httpClient = null;
+ }
+
+ /**
+ * Set the Escaper instance
+ *
+ * If null, resets the instance
+ *
+ * @param null|Escaper $escaper
+ */
+ public static function setEscaper(Escaper $escaper = null)
+ {
+ static::$escaper = $escaper;
+ }
+
+ /**
+ * Get the Escaper instance
+ *
+ * If none registered, lazy-loads an instance.
+ *
+ * @return Escaper
+ */
+ public static function getEscaper()
+ {
+ if (null === static::$escaper) {
+ static::setEscaper(new Escaper());
+ }
+ return static::$escaper;
+ }
+
+ /**
+ * RFC 3986 safe url encoding method
+ *
+ * @param string $string
+ * @return string
+ */
+ public static function urlencode($string)
+ {
+ $escaper = static::getEscaper();
+ $rawencoded = $escaper->escapeUrl($string);
+ $rfcencoded = str_replace('%7E', '~', $rawencoded);
+ return $rfcencoded;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Publisher.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Publisher.php
new file mode 100644
index 0000000..ec9c4e1
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Publisher.php
@@ -0,0 +1,397 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub;
+
+use Traversable;
+use Zend\Feed\Uri;
+use Zend\Http\Request as HttpRequest;
+use Zend\Stdlib\ArrayUtils;
+
+class Publisher
+{
+ /**
+ * An array of URLs for all Hub Servers used by the Publisher, and to
+ * which all topic update notifications will be sent.
+ *
+ * @var array
+ */
+ protected $hubUrls = array();
+
+ /**
+ * An array of topic (Atom or RSS feed) URLs which have been updated and
+ * whose updated status will be notified to all Hub Servers.
+ *
+ * @var array
+ */
+ protected $updatedTopicUrls = array();
+
+ /**
+ * An array of any errors including keys for 'response', 'hubUrl'.
+ * The response is the actual Zend\Http\Response object.
+ *
+ * @var array
+ */
+ protected $errors = array();
+
+ /**
+ * An array of topic (Atom or RSS feed) URLs which have been updated and
+ * whose updated status will be notified to all Hub Servers.
+ *
+ * @var array
+ */
+ protected $parameters = array();
+
+ /**
+ * Constructor; accepts an array or Zend\Config instance to preset
+ * options for the Publisher without calling all supported setter
+ * methods in turn.
+ *
+ * @param array|Traversable $options
+ */
+ public function __construct($options = null)
+ {
+ if ($options !== null) {
+ $this->setOptions($options);
+ }
+ }
+
+ /**
+ * Process any injected configuration options
+ *
+ * @param array|Traversable $options Options array or Traversable object
+ * @return Publisher
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setOptions($options)
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ }
+
+ if (!is_array($options)) {
+ throw new Exception\InvalidArgumentException('Array or Traversable object'
+ . 'expected, got ' . gettype($options));
+ }
+ if (array_key_exists('hubUrls', $options)) {
+ $this->addHubUrls($options['hubUrls']);
+ }
+ if (array_key_exists('updatedTopicUrls', $options)) {
+ $this->addUpdatedTopicUrls($options['updatedTopicUrls']);
+ }
+ if (array_key_exists('parameters', $options)) {
+ $this->setParameters($options['parameters']);
+ }
+ return $this;
+ }
+
+ /**
+ * Add a Hub Server URL supported by Publisher
+ *
+ * @param string $url
+ * @return Publisher
+ * @throws Exception\InvalidArgumentException
+ */
+ public function addHubUrl($url)
+ {
+ if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "url"'
+ . ' of "' . $url . '" must be a non-empty string and a valid'
+ . 'URL');
+ }
+ $this->hubUrls[] = $url;
+ return $this;
+ }
+
+ /**
+ * Add an array of Hub Server URLs supported by Publisher
+ *
+ * @param array $urls
+ * @return Publisher
+ */
+ public function addHubUrls(array $urls)
+ {
+ foreach ($urls as $url) {
+ $this->addHubUrl($url);
+ }
+ return $this;
+ }
+
+ /**
+ * Remove a Hub Server URL
+ *
+ * @param string $url
+ * @return Publisher
+ */
+ public function removeHubUrl($url)
+ {
+ if (!in_array($url, $this->getHubUrls())) {
+ return $this;
+ }
+ $key = array_search($url, $this->hubUrls);
+ unset($this->hubUrls[$key]);
+ return $this;
+ }
+
+ /**
+ * Return an array of unique Hub Server URLs currently available
+ *
+ * @return array
+ */
+ public function getHubUrls()
+ {
+ $this->hubUrls = array_unique($this->hubUrls);
+ return $this->hubUrls;
+ }
+
+ /**
+ * Add a URL to a topic (Atom or RSS feed) which has been updated
+ *
+ * @param string $url
+ * @return Publisher
+ * @throws Exception\InvalidArgumentException
+ */
+ public function addUpdatedTopicUrl($url)
+ {
+ if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "url"'
+ . ' of "' . $url . '" must be a non-empty string and a valid'
+ . 'URL');
+ }
+ $this->updatedTopicUrls[] = $url;
+ return $this;
+ }
+
+ /**
+ * Add an array of Topic URLs which have been updated
+ *
+ * @param array $urls
+ * @return Publisher
+ */
+ public function addUpdatedTopicUrls(array $urls)
+ {
+ foreach ($urls as $url) {
+ $this->addUpdatedTopicUrl($url);
+ }
+ return $this;
+ }
+
+ /**
+ * Remove an updated topic URL
+ *
+ * @param string $url
+ * @return Publisher
+ */
+ public function removeUpdatedTopicUrl($url)
+ {
+ if (!in_array($url, $this->getUpdatedTopicUrls())) {
+ return $this;
+ }
+ $key = array_search($url, $this->updatedTopicUrls);
+ unset($this->updatedTopicUrls[$key]);
+ return $this;
+ }
+
+ /**
+ * Return an array of unique updated topic URLs currently available
+ *
+ * @return array
+ */
+ public function getUpdatedTopicUrls()
+ {
+ $this->updatedTopicUrls = array_unique($this->updatedTopicUrls);
+ return $this->updatedTopicUrls;
+ }
+
+ /**
+ * Notifies a single Hub Server URL of changes
+ *
+ * @param string $url The Hub Server's URL
+ * @return void
+ * @throws Exception\InvalidArgumentException
+ * @throws Exception\RuntimeException
+ */
+ public function notifyHub($url)
+ {
+ if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "url"'
+ . ' of "' . $url . '" must be a non-empty string and a valid'
+ . 'URL');
+ }
+ $client = $this->_getHttpClient();
+ $client->setUri($url);
+ $response = $client->getResponse();
+ if ($response->getStatusCode() !== 204) {
+ throw new Exception\RuntimeException('Notification to Hub Server '
+ . 'at "' . $url . '" appears to have failed with a status code of "'
+ . $response->getStatusCode() . '" and message "'
+ . $response->getContent() . '"');
+ }
+ }
+
+ /**
+ * Notifies all Hub Server URLs of changes
+ *
+ * If a Hub notification fails, certain data will be retained in an
+ * an array retrieved using getErrors(), if a failure occurs for any Hubs
+ * the isSuccess() check will return FALSE. This method is designed not
+ * to needlessly fail with an Exception/Error unless from Zend\Http\Client.
+ *
+ * @return void
+ * @throws Exception\RuntimeException
+ */
+ public function notifyAll()
+ {
+ $client = $this->_getHttpClient();
+ $hubs = $this->getHubUrls();
+ if (empty($hubs)) {
+ throw new Exception\RuntimeException('No Hub Server URLs'
+ . ' have been set so no notifications can be sent');
+ }
+ $this->errors = array();
+ foreach ($hubs as $url) {
+ $client->setUri($url);
+ $response = $client->getResponse();
+ if ($response->getStatusCode() !== 204) {
+ $this->errors[] = array(
+ 'response' => $response,
+ 'hubUrl' => $url
+ );
+ }
+ }
+ }
+
+ /**
+ * Add an optional parameter to the update notification requests
+ *
+ * @param string $name
+ * @param string|null $value
+ * @return Publisher
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setParameter($name, $value = null)
+ {
+ if (is_array($name)) {
+ $this->setParameters($name);
+ return $this;
+ }
+ if (empty($name) || !is_string($name)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "name"'
+ . ' of "' . $name . '" must be a non-empty string');
+ }
+ if ($value === null) {
+ $this->removeParameter($name);
+ return $this;
+ }
+ if (empty($value) || (!is_string($value) && $value !== null)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "value"'
+ . ' of "' . $value . '" must be a non-empty string');
+ }
+ $this->parameters[$name] = $value;
+ return $this;
+ }
+
+ /**
+ * Add an optional parameter to the update notification requests
+ *
+ * @param array $parameters
+ * @return Publisher
+ */
+ public function setParameters(array $parameters)
+ {
+ foreach ($parameters as $name => $value) {
+ $this->setParameter($name, $value);
+ }
+ return $this;
+ }
+
+ /**
+ * Remove an optional parameter for the notification requests
+ *
+ * @param string $name
+ * @return Publisher
+ * @throws Exception\InvalidArgumentException
+ */
+ public function removeParameter($name)
+ {
+ if (empty($name) || !is_string($name)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "name"'
+ . ' of "' . $name . '" must be a non-empty string');
+ }
+ if (array_key_exists($name, $this->parameters)) {
+ unset($this->parameters[$name]);
+ }
+ return $this;
+ }
+
+ /**
+ * Return an array of optional parameters for notification requests
+ *
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
+ /**
+ * Returns a boolean indicator of whether the notifications to Hub
+ * Servers were ALL successful. If even one failed, FALSE is returned.
+ *
+ * @return bool
+ */
+ public function isSuccess()
+ {
+ return !(count($this->errors) != 0);
+ }
+
+ /**
+ * Return an array of errors met from any failures, including keys:
+ * 'response' => the Zend\Http\Response object from the failure
+ * 'hubUrl' => the URL of the Hub Server whose notification failed
+ *
+ * @return array
+ */
+ public function getErrors()
+ {
+ return $this->errors;
+ }
+
+ /**
+ * Get a basic prepared HTTP client for use
+ *
+ * @return \Zend\Http\Client
+ * @throws Exception\RuntimeException
+ */
+ protected function _getHttpClient()
+ {
+ $client = PubSubHubbub::getHttpClient();
+ $client->setMethod(HttpRequest::METHOD_POST);
+ $client->setOptions(array(
+ 'useragent' => 'Zend_Feed_Pubsubhubbub_Publisher/' . Version::VERSION,
+ ));
+ $params = array();
+ $params[] = 'hub.mode=publish';
+ $topics = $this->getUpdatedTopicUrls();
+ if (empty($topics)) {
+ throw new Exception\RuntimeException('No updated topic URLs'
+ . ' have been set');
+ }
+ foreach ($topics as $topicUrl) {
+ $params[] = 'hub.url=' . urlencode($topicUrl);
+ }
+ $optParams = $this->getParameters();
+ foreach ($optParams as $name => $value) {
+ $params[] = urlencode($name) . '=' . urlencode($value);
+ }
+ $paramString = implode('&', $params);
+ $client->setRawBody($paramString);
+ return $client;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Subscriber.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Subscriber.php
new file mode 100644
index 0000000..7171694
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Subscriber.php
@@ -0,0 +1,837 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub;
+
+use DateInterval;
+use DateTime;
+use Traversable;
+use Zend\Feed\Uri;
+use Zend\Http\Request as HttpRequest;
+use Zend\Stdlib\ArrayUtils;
+
+class Subscriber
+{
+ /**
+ * An array of URLs for all Hub Servers to subscribe/unsubscribe.
+ *
+ * @var array
+ */
+ protected $hubUrls = array();
+
+ /**
+ * An array of optional parameters to be included in any
+ * (un)subscribe requests.
+ *
+ * @var array
+ */
+ protected $parameters = array();
+
+ /**
+ * The URL of the topic (Rss or Atom feed) which is the subject of
+ * our current intent to subscribe to/unsubscribe from updates from
+ * the currently configured Hub Servers.
+ *
+ * @var string
+ */
+ protected $topicUrl = '';
+
+ /**
+ * The URL Hub Servers must use when communicating with this Subscriber
+ *
+ * @var string
+ */
+ protected $callbackUrl = '';
+
+ /**
+ * The number of seconds for which the subscriber would like to have the
+ * subscription active. Defaults to null, i.e. not sent, to setup a
+ * permanent subscription if possible.
+ *
+ * @var int
+ */
+ protected $leaseSeconds = null;
+
+ /**
+ * The preferred verification mode (sync or async). By default, this
+ * Subscriber prefers synchronous verification, but is considered
+ * desirable to support asynchronous verification if possible.
+ *
+ * Zend\Feed\Pubsubhubbub\Subscriber will always send both modes, whose
+ * order of occurrence in the parameter list determines this preference.
+ *
+ * @var string
+ */
+ protected $preferredVerificationMode = PubSubHubbub::VERIFICATION_MODE_SYNC;
+
+ /**
+ * An array of any errors including keys for 'response', 'hubUrl'.
+ * The response is the actual Zend\Http\Response object.
+ *
+ * @var array
+ */
+ protected $errors = array();
+
+ /**
+ * An array of Hub Server URLs for Hubs operating at this time in
+ * asynchronous verification mode.
+ *
+ * @var array
+ */
+ protected $asyncHubs = array();
+
+ /**
+ * An instance of Zend\Feed\Pubsubhubbub\Model\SubscriptionPersistence used to background
+ * save any verification tokens associated with a subscription or other.
+ *
+ * @var \Zend\Feed\PubSubHubbub\Model\SubscriptionPersistenceInterface
+ */
+ protected $storage = null;
+
+ /**
+ * An array of authentication credentials for HTTP Basic Authentication
+ * if required by specific Hubs. The array is indexed by Hub Endpoint URI
+ * and the value is a simple array of the username and password to apply.
+ *
+ * @var array
+ */
+ protected $authentications = array();
+
+ /**
+ * Tells the Subscriber to append any subscription identifier to the path
+ * of the base Callback URL. E.g. an identifier "subkey1" would be added
+ * to the callback URL "http://www.example.com/callback" to create a subscription
+ * specific Callback URL of "http://www.example.com/callback/subkey1".
+ *
+ * This is required for all Hubs using the Pubsubhubbub 0.1 Specification.
+ * It should be manually intercepted and passed to the Callback class using
+ * Zend\Feed\Pubsubhubbub\Subscriber\Callback::setSubscriptionKey(). Will
+ * require a route in the form "callback/:subkey" to allow the parameter be
+ * retrieved from an action using the Zend\Controller\Action::\getParam()
+ * method.
+ *
+ * @var string
+ */
+ protected $usePathParameter = false;
+
+ /**
+ * Constructor; accepts an array or Traversable instance to preset
+ * options for the Subscriber without calling all supported setter
+ * methods in turn.
+ *
+ * @param array|Traversable $options
+ */
+ public function __construct($options = null)
+ {
+ if ($options !== null) {
+ $this->setOptions($options);
+ }
+ }
+
+ /**
+ * Process any injected configuration options
+ *
+ * @param array|Traversable $options
+ * @return Subscriber
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setOptions($options)
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ }
+
+ if (!is_array($options)) {
+ throw new Exception\InvalidArgumentException('Array or Traversable object'
+ . 'expected, got ' . gettype($options));
+ }
+ if (array_key_exists('hubUrls', $options)) {
+ $this->addHubUrls($options['hubUrls']);
+ }
+ if (array_key_exists('callbackUrl', $options)) {
+ $this->setCallbackUrl($options['callbackUrl']);
+ }
+ if (array_key_exists('topicUrl', $options)) {
+ $this->setTopicUrl($options['topicUrl']);
+ }
+ if (array_key_exists('storage', $options)) {
+ $this->setStorage($options['storage']);
+ }
+ if (array_key_exists('leaseSeconds', $options)) {
+ $this->setLeaseSeconds($options['leaseSeconds']);
+ }
+ if (array_key_exists('parameters', $options)) {
+ $this->setParameters($options['parameters']);
+ }
+ if (array_key_exists('authentications', $options)) {
+ $this->addAuthentications($options['authentications']);
+ }
+ if (array_key_exists('usePathParameter', $options)) {
+ $this->usePathParameter($options['usePathParameter']);
+ }
+ if (array_key_exists('preferredVerificationMode', $options)) {
+ $this->setPreferredVerificationMode(
+ $options['preferredVerificationMode']
+ );
+ }
+ return $this;
+ }
+
+ /**
+ * Set the topic URL (RSS or Atom feed) to which the intended (un)subscribe
+ * event will relate
+ *
+ * @param string $url
+ * @return Subscriber
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setTopicUrl($url)
+ {
+ if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "url"'
+ .' of "' . $url . '" must be a non-empty string and a valid'
+ .' URL');
+ }
+ $this->topicUrl = $url;
+ return $this;
+ }
+
+ /**
+ * Set the topic URL (RSS or Atom feed) to which the intended (un)subscribe
+ * event will relate
+ *
+ * @return string
+ * @throws Exception\RuntimeException
+ */
+ public function getTopicUrl()
+ {
+ if (empty($this->topicUrl)) {
+ throw new Exception\RuntimeException('A valid Topic (RSS or Atom'
+ . ' feed) URL MUST be set before attempting any operation');
+ }
+ return $this->topicUrl;
+ }
+
+ /**
+ * Set the number of seconds for which any subscription will remain valid
+ *
+ * @param int $seconds
+ * @return Subscriber
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setLeaseSeconds($seconds)
+ {
+ $seconds = intval($seconds);
+ if ($seconds <= 0) {
+ throw new Exception\InvalidArgumentException('Expected lease seconds'
+ . ' must be an integer greater than zero');
+ }
+ $this->leaseSeconds = $seconds;
+ return $this;
+ }
+
+ /**
+ * Get the number of lease seconds on subscriptions
+ *
+ * @return int
+ */
+ public function getLeaseSeconds()
+ {
+ return $this->leaseSeconds;
+ }
+
+ /**
+ * Set the callback URL to be used by Hub Servers when communicating with
+ * this Subscriber
+ *
+ * @param string $url
+ * @return Subscriber
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setCallbackUrl($url)
+ {
+ if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "url"'
+ . ' of "' . $url . '" must be a non-empty string and a valid'
+ . ' URL');
+ }
+ $this->callbackUrl = $url;
+ return $this;
+ }
+
+ /**
+ * Get the callback URL to be used by Hub Servers when communicating with
+ * this Subscriber
+ *
+ * @return string
+ * @throws Exception\RuntimeException
+ */
+ public function getCallbackUrl()
+ {
+ if (empty($this->callbackUrl)) {
+ throw new Exception\RuntimeException('A valid Callback URL MUST be'
+ . ' set before attempting any operation');
+ }
+ return $this->callbackUrl;
+ }
+
+ /**
+ * Set preferred verification mode (sync or async). By default, this
+ * Subscriber prefers synchronous verification, but does support
+ * asynchronous if that's the Hub Server's utilised mode.
+ *
+ * Zend\Feed\Pubsubhubbub\Subscriber will always send both modes, whose
+ * order of occurrence in the parameter list determines this preference.
+ *
+ * @param string $mode Should be 'sync' or 'async'
+ * @return Subscriber
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setPreferredVerificationMode($mode)
+ {
+ if ($mode !== PubSubHubbub::VERIFICATION_MODE_SYNC
+ && $mode !== PubSubHubbub::VERIFICATION_MODE_ASYNC
+ ) {
+ throw new Exception\InvalidArgumentException('Invalid preferred'
+ . ' mode specified: "' . $mode . '" but should be one of'
+ . ' Zend\Feed\Pubsubhubbub::VERIFICATION_MODE_SYNC or'
+ . ' Zend\Feed\Pubsubhubbub::VERIFICATION_MODE_ASYNC');
+ }
+ $this->preferredVerificationMode = $mode;
+ return $this;
+ }
+
+ /**
+ * Get preferred verification mode (sync or async).
+ *
+ * @return string
+ */
+ public function getPreferredVerificationMode()
+ {
+ return $this->preferredVerificationMode;
+ }
+
+ /**
+ * Add a Hub Server URL supported by Publisher
+ *
+ * @param string $url
+ * @return Subscriber
+ * @throws Exception\InvalidArgumentException
+ */
+ public function addHubUrl($url)
+ {
+ if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "url"'
+ . ' of "' . $url . '" must be a non-empty string and a valid'
+ . ' URL');
+ }
+ $this->hubUrls[] = $url;
+ return $this;
+ }
+
+ /**
+ * Add an array of Hub Server URLs supported by Publisher
+ *
+ * @param array $urls
+ * @return Subscriber
+ */
+ public function addHubUrls(array $urls)
+ {
+ foreach ($urls as $url) {
+ $this->addHubUrl($url);
+ }
+ return $this;
+ }
+
+ /**
+ * Remove a Hub Server URL
+ *
+ * @param string $url
+ * @return Subscriber
+ */
+ public function removeHubUrl($url)
+ {
+ if (!in_array($url, $this->getHubUrls())) {
+ return $this;
+ }
+ $key = array_search($url, $this->hubUrls);
+ unset($this->hubUrls[$key]);
+ return $this;
+ }
+
+ /**
+ * Return an array of unique Hub Server URLs currently available
+ *
+ * @return array
+ */
+ public function getHubUrls()
+ {
+ $this->hubUrls = array_unique($this->hubUrls);
+ return $this->hubUrls;
+ }
+
+ /**
+ * Add authentication credentials for a given URL
+ *
+ * @param string $url
+ * @param array $authentication
+ * @return Subscriber
+ * @throws Exception\InvalidArgumentException
+ */
+ public function addAuthentication($url, array $authentication)
+ {
+ if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "url"'
+ . ' of "' . $url . '" must be a non-empty string and a valid'
+ . ' URL');
+ }
+ $this->authentications[$url] = $authentication;
+ return $this;
+ }
+
+ /**
+ * Add authentication credentials for hub URLs
+ *
+ * @param array $authentications
+ * @return Subscriber
+ */
+ public function addAuthentications(array $authentications)
+ {
+ foreach ($authentications as $url => $authentication) {
+ $this->addAuthentication($url, $authentication);
+ }
+ return $this;
+ }
+
+ /**
+ * Get all hub URL authentication credentials
+ *
+ * @return array
+ */
+ public function getAuthentications()
+ {
+ return $this->authentications;
+ }
+
+ /**
+ * Set flag indicating whether or not to use a path parameter
+ *
+ * @param bool $bool
+ * @return Subscriber
+ */
+ public function usePathParameter($bool = true)
+ {
+ $this->usePathParameter = $bool;
+ return $this;
+ }
+
+ /**
+ * Add an optional parameter to the (un)subscribe requests
+ *
+ * @param string $name
+ * @param string|null $value
+ * @return Subscriber
+ * @throws Exception\InvalidArgumentException
+ */
+ public function setParameter($name, $value = null)
+ {
+ if (is_array($name)) {
+ $this->setParameters($name);
+ return $this;
+ }
+ if (empty($name) || !is_string($name)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "name"'
+ . ' of "' . $name . '" must be a non-empty string');
+ }
+ if ($value === null) {
+ $this->removeParameter($name);
+ return $this;
+ }
+ if (empty($value) || (!is_string($value) && $value !== null)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "value"'
+ . ' of "' . $value . '" must be a non-empty string');
+ }
+ $this->parameters[$name] = $value;
+ return $this;
+ }
+
+ /**
+ * Add an optional parameter to the (un)subscribe requests
+ *
+ * @param array $parameters
+ * @return Subscriber
+ */
+ public function setParameters(array $parameters)
+ {
+ foreach ($parameters as $name => $value) {
+ $this->setParameter($name, $value);
+ }
+ return $this;
+ }
+
+ /**
+ * Remove an optional parameter for the (un)subscribe requests
+ *
+ * @param string $name
+ * @return Subscriber
+ * @throws Exception\InvalidArgumentException
+ */
+ public function removeParameter($name)
+ {
+ if (empty($name) || !is_string($name)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter "name"'
+ . ' of "' . $name . '" must be a non-empty string');
+ }
+ if (array_key_exists($name, $this->parameters)) {
+ unset($this->parameters[$name]);
+ }
+ return $this;
+ }
+
+ /**
+ * Return an array of optional parameters for (un)subscribe requests
+ *
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
+ /**
+ * Sets an instance of Zend\Feed\Pubsubhubbub\Model\SubscriptionPersistence used to background
+ * save any verification tokens associated with a subscription or other.
+ *
+ * @param Model\SubscriptionPersistenceInterface $storage
+ * @return Subscriber
+ */
+ public function setStorage(Model\SubscriptionPersistenceInterface $storage)
+ {
+ $this->storage = $storage;
+ return $this;
+ }
+
+ /**
+ * Gets an instance of Zend\Feed\Pubsubhubbub\Storage\StoragePersistence used
+ * to background save any verification tokens associated with a subscription
+ * or other.
+ *
+ * @return Model\SubscriptionPersistenceInterface
+ * @throws Exception\RuntimeException
+ */
+ public function getStorage()
+ {
+ if ($this->storage === null) {
+ throw new Exception\RuntimeException('No storage vehicle '
+ . 'has been set.');
+ }
+ return $this->storage;
+ }
+
+ /**
+ * Subscribe to one or more Hub Servers using the stored Hub URLs
+ * for the given Topic URL (RSS or Atom feed)
+ *
+ * @return void
+ */
+ public function subscribeAll()
+ {
+ $this->_doRequest('subscribe');
+ }
+
+ /**
+ * Unsubscribe from one or more Hub Servers using the stored Hub URLs
+ * for the given Topic URL (RSS or Atom feed)
+ *
+ * @return void
+ */
+ public function unsubscribeAll()
+ {
+ $this->_doRequest('unsubscribe');
+ }
+
+ /**
+ * Returns a boolean indicator of whether the notifications to Hub
+ * Servers were ALL successful. If even one failed, FALSE is returned.
+ *
+ * @return bool
+ */
+ public function isSuccess()
+ {
+ if (count($this->errors) > 0) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Return an array of errors met from any failures, including keys:
+ * 'response' => the Zend\Http\Response object from the failure
+ * 'hubUrl' => the URL of the Hub Server whose notification failed
+ *
+ * @return array
+ */
+ public function getErrors()
+ {
+ return $this->errors;
+ }
+
+ /**
+ * Return an array of Hub Server URLs who returned a response indicating
+ * operation in Asynchronous Verification Mode, i.e. they will not confirm
+ * any (un)subscription immediately but at a later time (Hubs may be
+ * doing this as a batch process when load balancing)
+ *
+ * @return array
+ */
+ public function getAsyncHubs()
+ {
+ return $this->asyncHubs;
+ }
+
+ /**
+ * Executes an (un)subscribe request
+ *
+ * @param string $mode
+ * @return void
+ * @throws Exception\RuntimeException
+ */
+ protected function _doRequest($mode)
+ {
+ $client = $this->_getHttpClient();
+ $hubs = $this->getHubUrls();
+ if (empty($hubs)) {
+ throw new Exception\RuntimeException('No Hub Server URLs'
+ . ' have been set so no subscriptions can be attempted');
+ }
+ $this->errors = array();
+ $this->asyncHubs = array();
+ foreach ($hubs as $url) {
+ if (array_key_exists($url, $this->authentications)) {
+ $auth = $this->authentications[$url];
+ $client->setAuth($auth[0], $auth[1]);
+ }
+ $client->setUri($url);
+ $client->setRawBody($params = $this->_getRequestParameters($url, $mode));
+ $response = $client->send();
+ if ($response->getStatusCode() !== 204
+ && $response->getStatusCode() !== 202
+ ) {
+ $this->errors[] = array(
+ 'response' => $response,
+ 'hubUrl' => $url,
+ );
+ /**
+ * At first I thought it was needed, but the backend storage will
+ * allow tracking async without any user interference. It's left
+ * here in case the user is interested in knowing what Hubs
+ * are using async verification modes so they may update Models and
+ * move these to asynchronous processes.
+ */
+ } elseif ($response->getStatusCode() == 202) {
+ $this->asyncHubs[] = array(
+ 'response' => $response,
+ 'hubUrl' => $url,
+ );
+ }
+ }
+ }
+
+ /**
+ * Get a basic prepared HTTP client for use
+ *
+ * @return \Zend\Http\Client
+ */
+ protected function _getHttpClient()
+ {
+ $client = PubSubHubbub::getHttpClient();
+ $client->setMethod(HttpRequest::METHOD_POST);
+ $client->setOptions(array('useragent' => 'Zend_Feed_Pubsubhubbub_Subscriber/'
+ . Version::VERSION));
+ return $client;
+ }
+
+ /**
+ * Return a list of standard protocol/optional parameters for addition to
+ * client's POST body that are specific to the current Hub Server URL
+ *
+ * @param string $hubUrl
+ * @param string $mode
+ * @return string
+ * @throws Exception\InvalidArgumentException
+ */
+ protected function _getRequestParameters($hubUrl, $mode)
+ {
+ if (!in_array($mode, array('subscribe', 'unsubscribe'))) {
+ throw new Exception\InvalidArgumentException('Invalid mode specified: "'
+ . $mode . '" which should have been "subscribe" or "unsubscribe"');
+ }
+
+ $params = array(
+ 'hub.mode' => $mode,
+ 'hub.topic' => $this->getTopicUrl(),
+ );
+
+ if ($this->getPreferredVerificationMode()
+ == PubSubHubbub::VERIFICATION_MODE_SYNC
+ ) {
+ $vmodes = array(
+ PubSubHubbub::VERIFICATION_MODE_SYNC,
+ PubSubHubbub::VERIFICATION_MODE_ASYNC,
+ );
+ } else {
+ $vmodes = array(
+ PubSubHubbub::VERIFICATION_MODE_ASYNC,
+ PubSubHubbub::VERIFICATION_MODE_SYNC,
+ );
+ }
+ $params['hub.verify'] = array();
+ foreach ($vmodes as $vmode) {
+ $params['hub.verify'][] = $vmode;
+ }
+
+ /**
+ * Establish a persistent verify_token and attach key to callback
+ * URL's path/query_string
+ */
+ $key = $this->_generateSubscriptionKey($params, $hubUrl);
+ $token = $this->_generateVerifyToken();
+ $params['hub.verify_token'] = $token;
+
+ // Note: query string only usable with PuSH 0.2 Hubs
+ if (!$this->usePathParameter) {
+ $params['hub.callback'] = $this->getCallbackUrl()
+ . '?xhub.subscription=' . PubSubHubbub::urlencode($key);
+ } else {
+ $params['hub.callback'] = rtrim($this->getCallbackUrl(), '/')
+ . '/' . PubSubHubbub::urlencode($key);
+ }
+ if ($mode == 'subscribe' && $this->getLeaseSeconds() !== null) {
+ $params['hub.lease_seconds'] = $this->getLeaseSeconds();
+ }
+
+ // hub.secret not currently supported
+ $optParams = $this->getParameters();
+ foreach ($optParams as $name => $value) {
+ $params[$name] = $value;
+ }
+
+ // store subscription to storage
+ $now = new DateTime();
+ $expires = null;
+ if (isset($params['hub.lease_seconds'])) {
+ $expires = $now->add(new DateInterval('PT' . $params['hub.lease_seconds'] . 'S'))
+ ->format('Y-m-d H:i:s');
+ }
+ $data = array(
+ 'id' => $key,
+ 'topic_url' => $params['hub.topic'],
+ 'hub_url' => $hubUrl,
+ 'created_time' => $now->format('Y-m-d H:i:s'),
+ 'lease_seconds' => $params['hub.lease_seconds'],
+ 'verify_token' => hash('sha256', $params['hub.verify_token']),
+ 'secret' => null,
+ 'expiration_time' => $expires,
+ 'subscription_state' => ($mode == 'unsubscribe')? PubSubHubbub::SUBSCRIPTION_TODELETE : PubSubHubbub::SUBSCRIPTION_NOTVERIFIED,
+ );
+ $this->getStorage()->setSubscription($data);
+
+ return $this->_toByteValueOrderedString(
+ $this->_urlEncode($params)
+ );
+ }
+
+ /**
+ * Simple helper to generate a verification token used in (un)subscribe
+ * requests to a Hub Server. Follows no particular method, which means
+ * it might be improved/changed in future.
+ *
+ * @return string
+ */
+ protected function _generateVerifyToken()
+ {
+ if (!empty($this->testStaticToken)) {
+ return $this->testStaticToken;
+ }
+ return uniqid(rand(), true) . time();
+ }
+
+ /**
+ * Simple helper to generate a verification token used in (un)subscribe
+ * requests to a Hub Server.
+ *
+ * @param array $params
+ * @param string $hubUrl The Hub Server URL for which this token will apply
+ * @return string
+ */
+ protected function _generateSubscriptionKey(array $params, $hubUrl)
+ {
+ $keyBase = $params['hub.topic'] . $hubUrl;
+ $key = md5($keyBase);
+
+ return $key;
+ }
+
+ /**
+ * URL Encode an array of parameters
+ *
+ * @param array $params
+ * @return array
+ */
+ protected function _urlEncode(array $params)
+ {
+ $encoded = array();
+ foreach ($params as $key => $value) {
+ if (is_array($value)) {
+ $ekey = PubSubHubbub::urlencode($key);
+ $encoded[$ekey] = array();
+ foreach ($value as $duplicateKey) {
+ $encoded[$ekey][]
+ = PubSubHubbub::urlencode($duplicateKey);
+ }
+ } else {
+ $encoded[PubSubHubbub::urlencode($key)]
+ = PubSubHubbub::urlencode($value);
+ }
+ }
+ return $encoded;
+ }
+
+ /**
+ * Order outgoing parameters
+ *
+ * @param array $params
+ * @return array
+ */
+ protected function _toByteValueOrderedString(array $params)
+ {
+ $return = array();
+ uksort($params, 'strnatcmp');
+ foreach ($params as $key => $value) {
+ if (is_array($value)) {
+ foreach ($value as $keyduplicate) {
+ $return[] = $key . '=' . $keyduplicate;
+ }
+ } else {
+ $return[] = $key . '=' . $value;
+ }
+ }
+ return implode('&', $return);
+ }
+
+ /**
+ * This is STRICTLY for testing purposes only...
+ */
+ protected $testStaticToken = null;
+
+ final public function setTestStaticToken($token)
+ {
+ $this->testStaticToken = (string) $token;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Subscriber/Callback.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Subscriber/Callback.php
new file mode 100644
index 0000000..4e15e58
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Subscriber/Callback.php
@@ -0,0 +1,316 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub\Subscriber;
+
+use Zend\Feed\PubSubHubbub;
+use Zend\Feed\PubSubHubbub\Exception;
+use Zend\Feed\Uri;
+
+class Callback extends PubSubHubbub\AbstractCallback
+{
+ /**
+ * Contains the content of any feeds sent as updates to the Callback URL
+ *
+ * @var string
+ */
+ protected $feedUpdate = null;
+
+ /**
+ * Holds a manually set subscription key (i.e. identifies a unique
+ * subscription) which is typical when it is not passed in the query string
+ * but is part of the Callback URL path, requiring manual retrieval e.g.
+ * using a route and the \Zend\Mvc\Router\RouteMatch::getParam() method.
+ *
+ * @var string
+ */
+ protected $subscriptionKey = null;
+
+ /**
+ * After verification, this is set to the verified subscription's data.
+ *
+ * @var array
+ */
+ protected $currentSubscriptionData = null;
+
+ /**
+ * Set a subscription key to use for the current callback request manually.
+ * Required if usePathParameter is enabled for the Subscriber.
+ *
+ * @param string $key
+ * @return \Zend\Feed\PubSubHubbub\Subscriber\Callback
+ */
+ public function setSubscriptionKey($key)
+ {
+ $this->subscriptionKey = $key;
+ return $this;
+ }
+
+ /**
+ * Handle any callback from a Hub Server responding to a subscription or
+ * unsubscription request. This should be the Hub Server confirming the
+ * the request prior to taking action on it.
+ *
+ * @param array $httpGetData GET data if available and not in $_GET
+ * @param bool $sendResponseNow Whether to send response now or when asked
+ * @return void
+ */
+ public function handle(array $httpGetData = null, $sendResponseNow = false)
+ {
+ if ($httpGetData === null) {
+ $httpGetData = $_GET;
+ }
+
+ /**
+ * Handle any feed updates (sorry for the mess :P)
+ *
+ * This DOES NOT attempt to process a feed update. Feed updates
+ * SHOULD be validated/processed by an asynchronous process so as
+ * to avoid holding up responses to the Hub.
+ */
+ $contentType = $this->_getHeader('Content-Type');
+ if (strtolower($_SERVER['REQUEST_METHOD']) == 'post'
+ && $this->_hasValidVerifyToken(null, false)
+ && (stripos($contentType, 'application/atom+xml') === 0
+ || stripos($contentType, 'application/rss+xml') === 0
+ || stripos($contentType, 'application/xml') === 0
+ || stripos($contentType, 'text/xml') === 0
+ || stripos($contentType, 'application/rdf+xml') === 0)
+ ) {
+ $this->setFeedUpdate($this->_getRawBody());
+ $this->getHttpResponse()->setHeader('X-Hub-On-Behalf-Of', $this->getSubscriberCount());
+ /**
+ * Handle any (un)subscribe confirmation requests
+ */
+ } elseif ($this->isValidHubVerification($httpGetData)) {
+ $this->getHttpResponse()->setContent($httpGetData['hub_challenge']);
+
+ switch (strtolower($httpGetData['hub_mode'])) {
+ case 'subscribe':
+ $data = $this->currentSubscriptionData;
+ $data['subscription_state'] = PubSubHubbub\PubSubHubbub::SUBSCRIPTION_VERIFIED;
+ if (isset($httpGetData['hub_lease_seconds'])) {
+ $data['lease_seconds'] = $httpGetData['hub_lease_seconds'];
+ }
+ $this->getStorage()->setSubscription($data);
+ break;
+ case 'unsubscribe':
+ $verifyTokenKey = $this->_detectVerifyTokenKey($httpGetData);
+ $this->getStorage()->deleteSubscription($verifyTokenKey);
+ break;
+ default:
+ throw new Exception\RuntimeException(sprintf(
+ 'Invalid hub_mode ("%s") provided',
+ $httpGetData['hub_mode']
+ ));
+ }
+ /**
+ * Hey, C'mon! We tried everything else!
+ */
+ } else {
+ $this->getHttpResponse()->setStatusCode(404);
+ }
+
+ if ($sendResponseNow) {
+ $this->sendResponse();
+ }
+ }
+
+ /**
+ * Checks validity of the request simply by making a quick pass and
+ * confirming the presence of all REQUIRED parameters.
+ *
+ * @param array $httpGetData
+ * @return bool
+ */
+ public function isValidHubVerification(array $httpGetData)
+ {
+ /**
+ * As per the specification, the hub.verify_token is OPTIONAL. This
+ * implementation of Pubsubhubbub considers it REQUIRED and will
+ * always send a hub.verify_token parameter to be echoed back
+ * by the Hub Server. Therefore, its absence is considered invalid.
+ */
+ if (strtolower($_SERVER['REQUEST_METHOD']) !== 'get') {
+ return false;
+ }
+ $required = array(
+ 'hub_mode',
+ 'hub_topic',
+ 'hub_challenge',
+ 'hub_verify_token',
+ );
+ foreach ($required as $key) {
+ if (!array_key_exists($key, $httpGetData)) {
+ return false;
+ }
+ }
+ if ($httpGetData['hub_mode'] !== 'subscribe'
+ && $httpGetData['hub_mode'] !== 'unsubscribe'
+ ) {
+ return false;
+ }
+ if ($httpGetData['hub_mode'] == 'subscribe'
+ && !array_key_exists('hub_lease_seconds', $httpGetData)
+ ) {
+ return false;
+ }
+ if (!Uri::factory($httpGetData['hub_topic'])->isValid()) {
+ return false;
+ }
+
+ /**
+ * Attempt to retrieve any Verification Token Key attached to Callback
+ * URL's path by our Subscriber implementation
+ */
+ if (!$this->_hasValidVerifyToken($httpGetData)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Sets a newly received feed (Atom/RSS) sent by a Hub as an update to a
+ * Topic we've subscribed to.
+ *
+ * @param string $feed
+ * @return \Zend\Feed\PubSubHubbub\Subscriber\Callback
+ */
+ public function setFeedUpdate($feed)
+ {
+ $this->feedUpdate = $feed;
+ return $this;
+ }
+
+ /**
+ * Check if any newly received feed (Atom/RSS) update was received
+ *
+ * @return bool
+ */
+ public function hasFeedUpdate()
+ {
+ if ($this->feedUpdate === null) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Gets a newly received feed (Atom/RSS) sent by a Hub as an update to a
+ * Topic we've subscribed to.
+ *
+ * @return string
+ */
+ public function getFeedUpdate()
+ {
+ return $this->feedUpdate;
+ }
+
+ /**
+ * Check for a valid verify_token. By default attempts to compare values
+ * with that sent from Hub, otherwise merely ascertains its existence.
+ *
+ * @param array $httpGetData
+ * @param bool $checkValue
+ * @return bool
+ */
+ protected function _hasValidVerifyToken(array $httpGetData = null, $checkValue = true)
+ {
+ $verifyTokenKey = $this->_detectVerifyTokenKey($httpGetData);
+ if (empty($verifyTokenKey)) {
+ return false;
+ }
+ $verifyTokenExists = $this->getStorage()->hasSubscription($verifyTokenKey);
+ if (!$verifyTokenExists) {
+ return false;
+ }
+ if ($checkValue) {
+ $data = $this->getStorage()->getSubscription($verifyTokenKey);
+ $verifyToken = $data['verify_token'];
+ if ($verifyToken !== hash('sha256', $httpGetData['hub_verify_token'])) {
+ return false;
+ }
+ $this->currentSubscriptionData = $data;
+ return true;
+ }
+ return true;
+ }
+
+ /**
+ * Attempt to detect the verification token key. This would be passed in
+ * the Callback URL (which we are handling with this class!) as a URI
+ * path part (the last part by convention).
+ *
+ * @param null|array $httpGetData
+ * @return false|string
+ */
+ protected function _detectVerifyTokenKey(array $httpGetData = null)
+ {
+ /**
+ * Available when sub keys encoding in Callback URL path
+ */
+ if (isset($this->subscriptionKey)) {
+ return $this->subscriptionKey;
+ }
+
+ /**
+ * Available only if allowed by PuSH 0.2 Hubs
+ */
+ if (is_array($httpGetData)
+ && isset($httpGetData['xhub_subscription'])
+ ) {
+ return $httpGetData['xhub_subscription'];
+ }
+
+ /**
+ * Available (possibly) if corrupted in transit and not part of $_GET
+ */
+ $params = $this->_parseQueryString();
+ if (isset($params['xhub.subscription'])) {
+ return rawurldecode($params['xhub.subscription']);
+ }
+
+ return false;
+ }
+
+ /**
+ * Build an array of Query String parameters.
+ * This bypasses $_GET which munges parameter names and cannot accept
+ * multiple parameters with the same key.
+ *
+ * @return array|void
+ */
+ protected function _parseQueryString()
+ {
+ $params = array();
+ $queryString = '';
+ if (isset($_SERVER['QUERY_STRING'])) {
+ $queryString = $_SERVER['QUERY_STRING'];
+ }
+ if (empty($queryString)) {
+ return array();
+ }
+ $parts = explode('&', $queryString);
+ foreach ($parts as $kvpair) {
+ $pair = explode('=', $kvpair);
+ $key = rawurldecode($pair[0]);
+ $value = rawurldecode($pair[1]);
+ if (isset($params[$key])) {
+ if (is_array($params[$key])) {
+ $params[$key][] = $value;
+ } else {
+ $params[$key] = array($params[$key], $value);
+ }
+ } else {
+ $params[$key] = $value;
+ }
+ }
+ return $params;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Version.php b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Version.php
new file mode 100644
index 0000000..026fe3b
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/PubSubHubbub/Version.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\PubSubHubbub;
+
+abstract class Version
+{
+ const VERSION = '2';
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/README.md b/core/vendor/zendframework/zend-feed/Zend/Feed/README.md
new file mode 100644
index 0000000..ffc73a9
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/README.md
@@ -0,0 +1,15 @@
+Feed Component from ZF2
+=======================
+
+This is the Feed component for ZF2.
+
+- File issues at https://github.com/zendframework/zf2/issues
+- Create pull requests against https://github.com/zendframework/zf2
+- Documentation is at http://framework.zend.com/docs
+
+LICENSE
+-------
+
+The files in this archive are released under the [Zend Framework
+license](http://framework.zend.com/license), which is a 3-clause BSD license.
+
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/AbstractEntry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/AbstractEntry.php
new file mode 100644
index 0000000..797562e
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/AbstractEntry.php
@@ -0,0 +1,224 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader;
+
+use DOMDocument;
+use DOMElement;
+use DOMXPath;
+
+abstract class AbstractEntry
+{
+ /**
+ * Feed entry data
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * DOM document object
+ *
+ * @var DOMDocument
+ */
+ protected $domDocument = null;
+
+ /**
+ * Entry instance
+ *
+ * @var DOMElement
+ */
+ protected $entry = null;
+
+ /**
+ * Pointer to the current entry
+ *
+ * @var int
+ */
+ protected $entryKey = 0;
+
+ /**
+ * XPath object
+ *
+ * @var DOMXPath
+ */
+ protected $xpath = null;
+
+ /**
+ * Registered extensions
+ *
+ * @var array
+ */
+ protected $extensions = array();
+
+ /**
+ * Constructor
+ *
+ * @param DOMElement $entry
+ * @param int $entryKey
+ * @param null|string $type
+ */
+ public function __construct(DOMElement $entry, $entryKey, $type = null)
+ {
+ $this->entry = $entry;
+ $this->entryKey = $entryKey;
+ $this->domDocument = $entry->ownerDocument;
+ if ($type !== null) {
+ $this->data['type'] = $type;
+ } else {
+ $this->data['type'] = Reader::detectType($entry);
+ }
+ $this->_loadExtensions();
+ }
+
+ /**
+ * Get the DOM
+ *
+ * @return DOMDocument
+ */
+ public function getDomDocument()
+ {
+ return $this->domDocument;
+ }
+
+ /**
+ * Get the entry element
+ *
+ * @return DOMElement
+ */
+ public function getElement()
+ {
+ return $this->entry;
+ }
+
+ /**
+ * Get the Entry's encoding
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ $assumed = $this->getDomDocument()->encoding;
+ if (empty($assumed)) {
+ $assumed = 'UTF-8';
+ }
+ return $assumed;
+ }
+
+ /**
+ * Get entry as xml
+ *
+ * @return string
+ */
+ public function saveXml()
+ {
+ $dom = new DOMDocument('1.0', $this->getEncoding());
+ $entry = $dom->importNode($this->getElement(), true);
+ $dom->appendChild($entry);
+ return $dom->saveXml();
+ }
+
+ /**
+ * Get the entry type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->data['type'];
+ }
+
+ /**
+ * Get the XPath query object
+ *
+ * @return DOMXPath
+ */
+ public function getXpath()
+ {
+ if (!$this->xpath) {
+ $this->setXpath(new DOMXPath($this->getDomDocument()));
+ }
+ return $this->xpath;
+ }
+
+ /**
+ * Set the XPath query
+ *
+ * @param DOMXPath $xpath
+ * @return \Zend\Feed\Reader\AbstractEntry
+ */
+ public function setXpath(DOMXPath $xpath)
+ {
+ $this->xpath = $xpath;
+ return $this;
+ }
+
+ /**
+ * Get registered extensions
+ *
+ * @return array
+ */
+ public function getExtensions()
+ {
+ return $this->extensions;
+ }
+
+ /**
+ * Return an Extension object with the matching name (postfixed with _Entry)
+ *
+ * @param string $name
+ * @return \Zend\Feed\Reader\Extension\AbstractEntry
+ */
+ public function getExtension($name)
+ {
+ if (array_key_exists($name . '\Entry', $this->extensions)) {
+ return $this->extensions[$name . '\Entry'];
+ }
+ return null;
+ }
+
+ /**
+ * Method overloading: call given method on first extension implementing it
+ *
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ * @throws Exception\BadMethodCallException if no extensions implements the method
+ */
+ public function __call($method, $args)
+ {
+ foreach ($this->extensions as $extension) {
+ if (method_exists($extension, $method)) {
+ return call_user_func_array(array($extension, $method), $args);
+ }
+ }
+ throw new Exception\BadMethodCallException('Method: ' . $method
+ . 'does not exist and could not be located on a registered Extension');
+ }
+
+ /**
+ * Load extensions from Zend\Feed\Reader\Reader
+ *
+ * @return void
+ */
+ protected function _loadExtensions()
+ {
+ $all = Reader::getExtensions();
+ $feed = $all['entry'];
+ foreach ($feed as $extension) {
+ if (in_array($extension, $all['core'])) {
+ continue;
+ }
+ $className = Reader::getPluginLoader()->getClassName($extension);
+ $this->extensions[$extension] = new $className(
+ $this->getElement(), $this->entryKey, $this->data['type']
+ );
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/AbstractFeed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/AbstractFeed.php
new file mode 100644
index 0000000..6a5cee3
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/AbstractFeed.php
@@ -0,0 +1,300 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader;
+
+use DOMDocument;
+use DOMElement;
+use DOMXPath;
+
+abstract class AbstractFeed implements Feed\FeedInterface
+{
+ /**
+ * Parsed feed data
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * Parsed feed data in the shape of a DOMDocument
+ *
+ * @var DOMDocument
+ */
+ protected $domDocument = null;
+
+ /**
+ * An array of parsed feed entries
+ *
+ * @var array
+ */
+ protected $entries = array();
+
+ /**
+ * A pointer for the iterator to keep track of the entries array
+ *
+ * @var int
+ */
+ protected $entriesKey = 0;
+
+ /**
+ * The base XPath query used to retrieve feed data
+ *
+ * @var DOMXPath
+ */
+ protected $xpath = null;
+
+ /**
+ * Array of loaded extensions
+ *
+ * @var array
+ */
+ protected $extensions = array();
+
+ /**
+ * Original Source URI (set if imported from a URI)
+ *
+ * @var string
+ */
+ protected $originalSourceUri = null;
+
+ /**
+ * Constructor
+ *
+ * @param DomDocument $domDocument The DOM object for the feed's XML
+ * @param string $type Feed type
+ */
+ public function __construct(DOMDocument $domDocument, $type = null)
+ {
+ $this->domDocument = $domDocument;
+ $this->xpath = new DOMXPath($this->domDocument);
+
+ if ($type !== null) {
+ $this->data['type'] = $type;
+ } else {
+ $this->data['type'] = Reader::detectType($this->domDocument);
+ }
+ $this->registerNamespaces();
+ $this->indexEntries();
+ $this->loadExtensions();
+ }
+
+ /**
+ * Set an original source URI for the feed being parsed. This value
+ * is returned from getFeedLink() method if the feed does not carry
+ * a self-referencing URI.
+ *
+ * @param string $uri
+ */
+ public function setOriginalSourceUri($uri)
+ {
+ $this->originalSourceUri = $uri;
+ }
+
+ /**
+ * Get an original source URI for the feed being parsed. Returns null if
+ * unset or the feed was not imported from a URI.
+ *
+ * @return string|null
+ */
+ public function getOriginalSourceUri()
+ {
+ return $this->originalSourceUri;
+ }
+
+ /**
+ * Get the number of feed entries.
+ * Required by the Iterator interface.
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->entries);
+ }
+
+ /**
+ * Return the current entry
+ *
+ * @return \Zend\Feed\Reader\AbstractEntry
+ */
+ public function current()
+ {
+ if (substr($this->getType(), 0, 3) == 'rss') {
+ $reader = new Entry\RSS($this->entries[$this->key()], $this->key(), $this->getType());
+ } else {
+ $reader = new Entry\Atom($this->entries[$this->key()], $this->key(), $this->getType());
+ }
+
+ $reader->setXpath($this->xpath);
+
+ return $reader;
+ }
+
+ /**
+ * Get the DOM
+ *
+ * @return DOMDocument
+ */
+ public function getDomDocument()
+ {
+ return $this->domDocument;
+ }
+
+ /**
+ * Get the Feed's encoding
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ $assumed = $this->getDomDocument()->encoding;
+ if (empty($assumed)) {
+ $assumed = 'UTF-8';
+ }
+ return $assumed;
+ }
+
+ /**
+ * Get feed as xml
+ *
+ * @return string
+ */
+ public function saveXml()
+ {
+ return $this->getDomDocument()->saveXml();
+ }
+
+ /**
+ * Get the DOMElement representing the items/feed element
+ *
+ * @return DOMElement
+ */
+ public function getElement()
+ {
+ return $this->getDomDocument()->documentElement;
+ }
+
+ /**
+ * Get the DOMXPath object for this feed
+ *
+ * @return DOMXPath
+ */
+ public function getXpath()
+ {
+ return $this->xpath;
+ }
+
+ /**
+ * Get the feed type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->data['type'];
+ }
+
+ /**
+ * Return the current feed key
+ *
+ * @return int
+ */
+ public function key()
+ {
+ return $this->entriesKey;
+ }
+
+ /**
+ * Move the feed pointer forward
+ *
+ */
+ public function next()
+ {
+ ++$this->entriesKey;
+ }
+
+ /**
+ * Reset the pointer in the feed object
+ *
+ */
+ public function rewind()
+ {
+ $this->entriesKey = 0;
+ }
+
+ /**
+ * Check to see if the iterator is still valid
+ *
+ * @return bool
+ */
+ public function valid()
+ {
+ return 0 <= $this->entriesKey && $this->entriesKey < $this->count();
+ }
+
+ public function getExtensions()
+ {
+ return $this->extensions;
+ }
+
+ public function __call($method, $args)
+ {
+ foreach ($this->extensions as $extension) {
+ if (method_exists($extension, $method)) {
+ return call_user_func_array(array($extension, $method), $args);
+ }
+ }
+ throw new Exception\BadMethodCallException('Method: ' . $method
+ . 'does not exist and could not be located on a registered Extension');
+ }
+
+ /**
+ * Return an Extension object with the matching name (postfixed with _Feed)
+ *
+ * @param string $name
+ * @return \Zend\Feed\Reader\Extension\AbstractFeed
+ */
+ public function getExtension($name)
+ {
+ if (array_key_exists($name . '\Feed', $this->extensions)) {
+ return $this->extensions[$name . '\Feed'];
+ }
+ return null;
+ }
+
+ protected function loadExtensions()
+ {
+ $all = Reader::getExtensions();
+ $manager = Reader::getExtensionManager();
+ $feed = $all['feed'];
+ foreach ($feed as $extension) {
+ if (in_array($extension, $all['core'])) {
+ continue;
+ }
+ $plugin = $manager->get($extension);
+ $plugin->setDomDocument($this->getDomDocument());
+ $plugin->setType($this->data['type']);
+ $plugin->setXpath($this->xpath);
+ $this->extensions[$extension] = $plugin;
+ }
+ }
+
+ /**
+ * Read all entries to the internal entries array
+ *
+ */
+ abstract protected function indexEntries();
+
+ /**
+ * Register the default namespaces for the current feed format
+ *
+ */
+ abstract protected function registerNamespaces();
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection.php
new file mode 100644
index 0000000..32144df
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader;
+
+class Collection extends \ArrayObject
+{
+
+
+
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/AbstractCollection.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/AbstractCollection.php
new file mode 100644
index 0000000..8c64ec9
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/AbstractCollection.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Collection;
+
+abstract class AbstractCollection extends \ArrayObject
+{
+
+ /**
+ * Return a simple array of the most relevant slice of
+ * the collection values. For example, feed categories contain
+ * the category name, domain/URI, and other data. This method would
+ * merely return the most useful data - i.e. the category names.
+ *
+ * @return array
+ */
+ abstract public function getValues();
+
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Author.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Author.php
new file mode 100644
index 0000000..15aa328
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Author.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Collection;
+
+class Author extends AbstractCollection
+{
+
+ /**
+ * Return a simple array of the most relevant slice of
+ * the author values, i.e. all author names.
+ *
+ * @return array
+ */
+ public function getValues()
+ {
+ $authors = array();
+ foreach ($this->getIterator() as $element) {
+ $authors[] = $element['name'];
+ }
+ return array_unique($authors);
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Category.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Category.php
new file mode 100644
index 0000000..2739bc8
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Category.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Collection;
+
+class Category extends AbstractCollection
+{
+
+ /**
+ * Return a simple array of the most relevant slice of
+ * the collection values. For example, feed categories contain
+ * the category name, domain/URI, and other data. This method would
+ * merely return the most useful data - i.e. the category names.
+ *
+ * @return array
+ */
+ public function getValues()
+ {
+ $categories = array();
+ foreach ($this->getIterator() as $element) {
+ if (isset($element['label']) && !empty($element['label'])) {
+ $categories[] = $element['label'];
+ } else {
+ $categories[] = $element['term'];
+ }
+ }
+ return array_unique($categories);
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Collection.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Collection.php
new file mode 100644
index 0000000..820a695
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Collection/Collection.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Collection;
+
+class Collection extends \ArrayObject
+{
+
+
+
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/AbstractEntry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/AbstractEntry.php
new file mode 100644
index 0000000..68ff4f9
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/AbstractEntry.php
@@ -0,0 +1,230 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Entry;
+
+use DOMDocument;
+use DOMElement;
+use DOMXPath;
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Exception;
+
+abstract class AbstractEntry
+{
+ /**
+ * Feed entry data
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * DOM document object
+ *
+ * @var DOMDocument
+ */
+ protected $domDocument = null;
+
+ /**
+ * Entry instance
+ *
+ * @var DOMElement
+ */
+ protected $entry = null;
+
+ /**
+ * Pointer to the current entry
+ *
+ * @var int
+ */
+ protected $entryKey = 0;
+
+ /**
+ * XPath object
+ *
+ * @var DOMXPath
+ */
+ protected $xpath = null;
+
+ /**
+ * Registered extensions
+ *
+ * @var array
+ */
+ protected $extensions = array();
+
+ /**
+ * Constructor
+ *
+ * @param DOMElement $entry
+ * @param int $entryKey
+ * @param string $type
+ */
+ public function __construct(DOMElement $entry, $entryKey, $type = null)
+ {
+ $this->entry = $entry;
+ $this->entryKey = $entryKey;
+ $this->domDocument = $entry->ownerDocument;
+ if ($type !== null) {
+ $this->data['type'] = $type;
+ } elseif ($this->domDocument !== null) {
+ $this->data['type'] = Reader\Reader::detectType($this->domDocument);
+ } else {
+ $this->data['type'] = Reader\Reader::TYPE_ANY;
+ }
+ $this->loadExtensions();
+ }
+
+ /**
+ * Get the DOM
+ *
+ * @return DOMDocument
+ */
+ public function getDomDocument()
+ {
+ return $this->domDocument;
+ }
+
+ /**
+ * Get the entry element
+ *
+ * @return DOMElement
+ */
+ public function getElement()
+ {
+ return $this->entry;
+ }
+
+ /**
+ * Get the Entry's encoding
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ $assumed = $this->getDomDocument()->encoding;
+ if (empty($assumed)) {
+ $assumed = 'UTF-8';
+ }
+ return $assumed;
+ }
+
+ /**
+ * Get entry as xml
+ *
+ * @return string
+ */
+ public function saveXml()
+ {
+ $dom = new DOMDocument('1.0', $this->getEncoding());
+ $entry = $dom->importNode($this->getElement(), true);
+ $dom->appendChild($entry);
+ return $dom->saveXml();
+ }
+
+ /**
+ * Get the entry type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->data['type'];
+ }
+
+ /**
+ * Get the XPath query object
+ *
+ * @return DOMXPath
+ */
+ public function getXpath()
+ {
+ if (!$this->xpath) {
+ $this->setXpath(new DOMXPath($this->getDomDocument()));
+ }
+ return $this->xpath;
+ }
+
+ /**
+ * Set the XPath query
+ *
+ * @param DOMXPath $xpath
+ * @return AbstractEntry
+ */
+ public function setXpath(DOMXPath $xpath)
+ {
+ $this->xpath = $xpath;
+ return $this;
+ }
+
+ /**
+ * Get registered extensions
+ *
+ * @return array
+ */
+ public function getExtensions()
+ {
+ return $this->extensions;
+ }
+
+ /**
+ * Return an Extension object with the matching name (postfixed with _Entry)
+ *
+ * @param string $name
+ * @return Reader\Extension\AbstractEntry
+ */
+ public function getExtension($name)
+ {
+ if (array_key_exists($name . '\\Entry', $this->extensions)) {
+ return $this->extensions[$name . '\\Entry'];
+ }
+ return null;
+ }
+
+ /**
+ * Method overloading: call given method on first extension implementing it
+ *
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ * @throws Exception\RuntimeException if no extensions implements the method
+ */
+ public function __call($method, $args)
+ {
+ foreach ($this->extensions as $extension) {
+ if (method_exists($extension, $method)) {
+ return call_user_func_array(array($extension, $method), $args);
+ }
+ }
+ throw new Exception\RuntimeException('Method: ' . $method
+ . ' does not exist and could not be located on a registered Extension');
+ }
+
+ /**
+ * Load extensions from Zend\Feed\Reader\Reader
+ *
+ * @return void
+ */
+ protected function loadExtensions()
+ {
+ $all = Reader\Reader::getExtensions();
+ $manager = Reader\Reader::getExtensionManager();
+ $feed = $all['entry'];
+ foreach ($feed as $extension) {
+ if (in_array($extension, $all['core'])) {
+ continue;
+ }
+ $plugin = $manager->get($extension);
+ $plugin->setEntryElement($this->getElement());
+ $plugin->setEntryKey($this->entryKey);
+ $plugin->setType($this->data['type']);
+ $this->extensions[$extension] = $plugin;
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/Atom.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/Atom.php
new file mode 100644
index 0000000..fcd5f60
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/Atom.php
@@ -0,0 +1,370 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Entry;
+
+use DOMElement;
+use DOMXPath;
+use Zend\Feed\Reader;
+
+class Atom extends AbstractEntry implements EntryInterface
+{
+ /**
+ * XPath query
+ *
+ * @var string
+ */
+ protected $xpathQuery = '';
+
+ /**
+ * Constructor
+ *
+ * @param DOMElement $entry
+ * @param int $entryKey
+ * @param string $type
+ */
+ public function __construct(DOMElement $entry, $entryKey, $type = null)
+ {
+ parent::__construct($entry, $entryKey, $type);
+
+ // Everyone by now should know XPath indices start from 1 not 0
+ $this->xpathQuery = '//atom:entry[' . ($this->entryKey + 1) . ']';
+
+ $manager = Reader\Reader::getExtensionManager();
+ $extensions = array('Atom\Entry', 'Thread\Entry', 'DublinCore\Entry');
+
+ foreach ($extensions as $name) {
+ $extension = $manager->get($name);
+ $extension->setEntryElement($entry);
+ $extension->setEntryKey($entryKey);
+ $extension->setType($type);
+ $this->extensions[$name] = $extension;
+ }
+ }
+
+ /**
+ * Get the specified author
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getAuthor($index = 0)
+ {
+ $authors = $this->getAuthors();
+
+ if (isset($authors[$index])) {
+ return $authors[$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return array
+ */
+ public function getAuthors()
+ {
+ if (array_key_exists('authors', $this->data)) {
+ return $this->data['authors'];
+ }
+
+ $people = $this->getExtension('Atom')->getAuthors();
+
+ $this->data['authors'] = $people;
+
+ return $this->data['authors'];
+ }
+
+ /**
+ * Get the entry content
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ if (array_key_exists('content', $this->data)) {
+ return $this->data['content'];
+ }
+
+ $content = $this->getExtension('Atom')->getContent();
+
+ $this->data['content'] = $content;
+
+ return $this->data['content'];
+ }
+
+ /**
+ * Get the entry creation date
+ *
+ * @return string
+ */
+ public function getDateCreated()
+ {
+ if (array_key_exists('datecreated', $this->data)) {
+ return $this->data['datecreated'];
+ }
+
+ $dateCreated = $this->getExtension('Atom')->getDateCreated();
+
+ $this->data['datecreated'] = $dateCreated;
+
+ return $this->data['datecreated'];
+ }
+
+ /**
+ * Get the entry modification date
+ *
+ * @return string
+ */
+ public function getDateModified()
+ {
+ if (array_key_exists('datemodified', $this->data)) {
+ return $this->data['datemodified'];
+ }
+
+ $dateModified = $this->getExtension('Atom')->getDateModified();
+
+ $this->data['datemodified'] = $dateModified;
+
+ return $this->data['datemodified'];
+ }
+
+ /**
+ * Get the entry description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ if (array_key_exists('description', $this->data)) {
+ return $this->data['description'];
+ }
+
+ $description = $this->getExtension('Atom')->getDescription();
+
+ $this->data['description'] = $description;
+
+ return $this->data['description'];
+ }
+
+ /**
+ * Get the entry enclosure
+ *
+ * @return string
+ */
+ public function getEnclosure()
+ {
+ if (array_key_exists('enclosure', $this->data)) {
+ return $this->data['enclosure'];
+ }
+
+ $enclosure = $this->getExtension('Atom')->getEnclosure();
+
+ $this->data['enclosure'] = $enclosure;
+
+ return $this->data['enclosure'];
+ }
+
+ /**
+ * Get the entry ID
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ if (array_key_exists('id', $this->data)) {
+ return $this->data['id'];
+ }
+
+ $id = $this->getExtension('Atom')->getId();
+
+ $this->data['id'] = $id;
+
+ return $this->data['id'];
+ }
+
+ /**
+ * Get a specific link
+ *
+ * @param int $index
+ * @return string
+ */
+ public function getLink($index = 0)
+ {
+ if (!array_key_exists('links', $this->data)) {
+ $this->getLinks();
+ }
+
+ if (isset($this->data['links'][$index])) {
+ return $this->data['links'][$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get all links
+ *
+ * @return array
+ */
+ public function getLinks()
+ {
+ if (array_key_exists('links', $this->data)) {
+ return $this->data['links'];
+ }
+
+ $links = $this->getExtension('Atom')->getLinks();
+
+ $this->data['links'] = $links;
+
+ return $this->data['links'];
+ }
+
+ /**
+ * Get a permalink to the entry
+ *
+ * @return string
+ */
+ public function getPermalink()
+ {
+ return $this->getLink(0);
+ }
+
+ /**
+ * Get the entry title
+ *
+ * @return string
+ */
+ public function getTitle()
+ {
+ if (array_key_exists('title', $this->data)) {
+ return $this->data['title'];
+ }
+
+ $title = $this->getExtension('Atom')->getTitle();
+
+ $this->data['title'] = $title;
+
+ return $this->data['title'];
+ }
+
+ /**
+ * Get the number of comments/replies for current entry
+ *
+ * @return int
+ */
+ public function getCommentCount()
+ {
+ if (array_key_exists('commentcount', $this->data)) {
+ return $this->data['commentcount'];
+ }
+
+ $commentcount = $this->getExtension('Thread')->getCommentCount();
+
+ if (!$commentcount) {
+ $commentcount = $this->getExtension('Atom')->getCommentCount();
+ }
+
+ $this->data['commentcount'] = $commentcount;
+
+ return $this->data['commentcount'];
+ }
+
+ /**
+ * Returns a URI pointing to the HTML page where comments can be made on this entry
+ *
+ * @return string
+ */
+ public function getCommentLink()
+ {
+ if (array_key_exists('commentlink', $this->data)) {
+ return $this->data['commentlink'];
+ }
+
+ $commentlink = $this->getExtension('Atom')->getCommentLink();
+
+ $this->data['commentlink'] = $commentlink;
+
+ return $this->data['commentlink'];
+ }
+
+ /**
+ * Returns a URI pointing to a feed of all comments for this entry
+ *
+ * @return string
+ */
+ public function getCommentFeedLink()
+ {
+ if (array_key_exists('commentfeedlink', $this->data)) {
+ return $this->data['commentfeedlink'];
+ }
+
+ $commentfeedlink = $this->getExtension('Atom')->getCommentFeedLink();
+
+ $this->data['commentfeedlink'] = $commentfeedlink;
+
+ return $this->data['commentfeedlink'];
+ }
+
+ /**
+ * Get category data as a Reader\Reader_Collection_Category object
+ *
+ * @return Reader\Collection\Category
+ */
+ public function getCategories()
+ {
+ if (array_key_exists('categories', $this->data)) {
+ return $this->data['categories'];
+ }
+
+ $categoryCollection = $this->getExtension('Atom')->getCategories();
+
+ if (count($categoryCollection) == 0) {
+ $categoryCollection = $this->getExtension('DublinCore')->getCategories();
+ }
+
+ $this->data['categories'] = $categoryCollection;
+
+ return $this->data['categories'];
+ }
+
+ /**
+ * Get source feed metadata from the entry
+ *
+ * @return Reader\Feed\Atom\Source|null
+ */
+ public function getSource()
+ {
+ if (array_key_exists('source', $this->data)) {
+ return $this->data['source'];
+ }
+
+ $source = $this->getExtension('Atom')->getSource();
+
+ $this->data['source'] = $source;
+
+ return $this->data['source'];
+ }
+
+ /**
+ * Set the XPath query (incl. on all Extensions)
+ *
+ * @param DOMXPath $xpath
+ * @return void
+ */
+ public function setXpath(DOMXPath $xpath)
+ {
+ parent::setXpath($xpath);
+ foreach ($this->extensions as $extension) {
+ $extension->setXpath($this->xpath);
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/EntryInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/EntryInterface.php
new file mode 100644
index 0000000..29b437a
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/EntryInterface.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Entry;
+
+use Zend\Feed\Reader\Collection\Category;
+
+interface EntryInterface
+{
+ /**
+ * Get the specified author
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getAuthor($index = 0);
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return array
+ */
+ public function getAuthors();
+
+ /**
+ * Get the entry content
+ *
+ * @return string
+ */
+ public function getContent();
+
+ /**
+ * Get the entry creation date
+ *
+ * @return string
+ */
+ public function getDateCreated();
+
+ /**
+ * Get the entry modification date
+ *
+ * @return string
+ */
+ public function getDateModified();
+
+ /**
+ * Get the entry description
+ *
+ * @return string
+ */
+ public function getDescription();
+
+ /**
+ * Get the entry enclosure
+ *
+ * @return \stdClass
+ */
+ public function getEnclosure();
+
+ /**
+ * Get the entry ID
+ *
+ * @return string
+ */
+ public function getId();
+
+ /**
+ * Get a specific link
+ *
+ * @param int $index
+ * @return string
+ */
+ public function getLink($index = 0);
+
+ /**
+ * Get all links
+ *
+ * @return array
+ */
+ public function getLinks();
+
+ /**
+ * Get a permalink to the entry
+ *
+ * @return string
+ */
+ public function getPermalink();
+
+ /**
+ * Get the entry title
+ *
+ * @return string
+ */
+ public function getTitle();
+
+ /**
+ * Get the number of comments/replies for current entry
+ *
+ * @return int
+ */
+ public function getCommentCount();
+
+ /**
+ * Returns a URI pointing to the HTML page where comments can be made on this entry
+ *
+ * @return string
+ */
+ public function getCommentLink();
+
+ /**
+ * Returns a URI pointing to a feed of all comments for this entry
+ *
+ * @return string
+ */
+ public function getCommentFeedLink();
+
+ /**
+ * Get all categories
+ *
+ * @return Category
+ */
+ public function getCategories();
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/Rss.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/Rss.php
new file mode 100644
index 0000000..274d0d5
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Entry/Rss.php
@@ -0,0 +1,599 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Entry;
+
+use DateTime;
+use DOMElement;
+use DOMXPath;
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Exception;
+
+class Rss extends AbstractEntry implements EntryInterface
+{
+
+ /**
+ * XPath query for RDF
+ *
+ * @var string
+ */
+ protected $xpathQueryRdf = '';
+
+ /**
+ * XPath query for RSS
+ *
+ * @var string
+ */
+ protected $xpathQueryRss = '';
+
+ /**
+ * Constructor
+ *
+ * @param DOMElement $entry
+ * @param string $entryKey
+ * @param string $type
+ */
+ public function __construct(DOMElement $entry, $entryKey, $type = null)
+ {
+ parent::__construct($entry, $entryKey, $type);
+ $this->xpathQueryRss = '//item[' . ($this->entryKey+1) . ']';
+ $this->xpathQueryRdf = '//rss:item[' . ($this->entryKey+1) . ']';
+
+ $manager = Reader\Reader::getExtensionManager();
+ $extensions = array(
+ 'DublinCore\Entry',
+ 'Content\Entry',
+ 'Atom\Entry',
+ 'WellFormedWeb\Entry',
+ 'Slash\Entry',
+ 'Thread\Entry',
+ );
+ foreach ($extensions as $name) {
+ $extension = $manager->get($name);
+ $extension->setEntryElement($entry);
+ $extension->setEntryKey($entryKey);
+ $extension->setType($type);
+ $this->extensions[$name] = $extension;
+ }
+ }
+
+ /**
+ * Get an author entry
+ *
+ * @param int $index
+ * @return string
+ */
+ public function getAuthor($index = 0)
+ {
+ $authors = $this->getAuthors();
+
+ if (isset($authors[$index])) {
+ return $authors[$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return array
+ */
+ public function getAuthors()
+ {
+ if (array_key_exists('authors', $this->data)) {
+ return $this->data['authors'];
+ }
+
+ $authors = array();
+ $authorsDc = $this->getExtension('DublinCore')->getAuthors();
+ if (!empty($authorsDc)) {
+ foreach ($authorsDc as $author) {
+ $authors[] = array(
+ 'name' => $author['name']
+ );
+ }
+ }
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10
+ && $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $list = $this->xpath->query($this->xpathQueryRss . '//author');
+ } else {
+ $list = $this->xpath->query($this->xpathQueryRdf . '//rss:author');
+ }
+ if ($list->length) {
+ foreach ($list as $author) {
+ $string = trim($author->nodeValue);
+ $email = null;
+ $name = null;
+ $data = array();
+ // Pretty rough parsing - but it's a catchall
+ if (preg_match("/^.*@[^ ]*/", $string, $matches)) {
+ $data['email'] = trim($matches[0]);
+ if (preg_match("/\((.*)\)$/", $string, $matches)) {
+ $data['name'] = $matches[1];
+ }
+ $authors[] = $data;
+ }
+ }
+ }
+
+ if (count($authors) == 0) {
+ $authors = $this->getExtension('Atom')->getAuthors();
+ } else {
+ $authors = new Reader\Collection\Author(
+ Reader\Reader::arrayUnique($authors)
+ );
+ }
+
+ if (count($authors) == 0) {
+ $authors = null;
+ }
+
+ $this->data['authors'] = $authors;
+
+ return $this->data['authors'];
+ }
+
+ /**
+ * Get the entry content
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ if (array_key_exists('content', $this->data)) {
+ return $this->data['content'];
+ }
+
+ $content = $this->getExtension('Content')->getContent();
+
+ if (!$content) {
+ $content = $this->getDescription();
+ }
+
+ if (empty($content)) {
+ $content = $this->getExtension('Atom')->getContent();
+ }
+
+ $this->data['content'] = $content;
+
+ return $this->data['content'];
+ }
+
+ /**
+ * Get the entry's date of creation
+ *
+ * @return string
+ */
+ public function getDateCreated()
+ {
+ return $this->getDateModified();
+ }
+
+ /**
+ * Get the entry's date of modification
+ *
+ * @throws Exception\RuntimeException
+ * @return string
+ */
+ public function getDateModified()
+ {
+ if (array_key_exists('datemodified', $this->data)) {
+ return $this->data['datemodified'];
+ }
+
+ $dateModified = null;
+ $date = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10
+ && $this->getType() !== Reader\Reader::TYPE_RSS_090
+ ) {
+ $dateModified = $this->xpath->evaluate('string(' . $this->xpathQueryRss . '/pubDate)');
+ if ($dateModified) {
+ $dateModifiedParsed = strtotime($dateModified);
+ if ($dateModifiedParsed) {
+ $date = new DateTime('@' . $dateModifiedParsed);
+ } else {
+ $dateStandards = array(DateTime::RSS, DateTime::RFC822,
+ DateTime::RFC2822, null);
+ foreach ($dateStandards as $standard) {
+ try {
+ $date = date_create_from_format($standard, $dateModified);
+ break;
+ } catch (\Exception $e) {
+ if ($standard == null) {
+ throw new Exception\RuntimeException(
+ 'Could not load date due to unrecognised'
+ .' format (should follow RFC 822 or 2822):'
+ . $e->getMessage(),
+ 0, $e
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!$date) {
+ $date = $this->getExtension('DublinCore')->getDate();
+ }
+
+ if (!$date) {
+ $date = $this->getExtension('Atom')->getDateModified();
+ }
+
+ if (!$date) {
+ $date = null;
+ }
+
+ $this->data['datemodified'] = $date;
+
+ return $this->data['datemodified'];
+ }
+
+ /**
+ * Get the entry description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ if (array_key_exists('description', $this->data)) {
+ return $this->data['description'];
+ }
+
+ $description = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10
+ && $this->getType() !== Reader\Reader::TYPE_RSS_090
+ ) {
+ $description = $this->xpath->evaluate('string(' . $this->xpathQueryRss . '/description)');
+ } else {
+ $description = $this->xpath->evaluate('string(' . $this->xpathQueryRdf . '/rss:description)');
+ }
+
+ if (!$description) {
+ $description = $this->getExtension('DublinCore')->getDescription();
+ }
+
+ if (empty($description)) {
+ $description = $this->getExtension('Atom')->getDescription();
+ }
+
+ if (!$description) {
+ $description = null;
+ }
+
+ $this->data['description'] = $description;
+
+ return $this->data['description'];
+ }
+
+ /**
+ * Get the entry enclosure
+ * @return string
+ */
+ public function getEnclosure()
+ {
+ if (array_key_exists('enclosure', $this->data)) {
+ return $this->data['enclosure'];
+ }
+
+ $enclosure = null;
+
+ if ($this->getType() == Reader\Reader::TYPE_RSS_20) {
+ $nodeList = $this->xpath->query($this->xpathQueryRss . '/enclosure');
+
+ if ($nodeList->length > 0) {
+ $enclosure = new \stdClass();
+ $enclosure->url = $nodeList->item(0)->getAttribute('url');
+ $enclosure->length = $nodeList->item(0)->getAttribute('length');
+ $enclosure->type = $nodeList->item(0)->getAttribute('type');
+ }
+ }
+
+ if (!$enclosure) {
+ $enclosure = $this->getExtension('Atom')->getEnclosure();
+ }
+
+ $this->data['enclosure'] = $enclosure;
+
+ return $this->data['enclosure'];
+ }
+
+ /**
+ * Get the entry ID
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ if (array_key_exists('id', $this->data)) {
+ return $this->data['id'];
+ }
+
+ $id = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10
+ && $this->getType() !== Reader\Reader::TYPE_RSS_090
+ ) {
+ $id = $this->xpath->evaluate('string(' . $this->xpathQueryRss . '/guid)');
+ }
+
+ if (!$id) {
+ $id = $this->getExtension('DublinCore')->getId();
+ }
+
+ if (empty($id)) {
+ $id = $this->getExtension('Atom')->getId();
+ }
+
+ if (!$id) {
+ if ($this->getPermalink()) {
+ $id = $this->getPermalink();
+ } elseif ($this->getTitle()) {
+ $id = $this->getTitle();
+ } else {
+ $id = null;
+ }
+ }
+
+ $this->data['id'] = $id;
+
+ return $this->data['id'];
+ }
+
+ /**
+ * Get a specific link
+ *
+ * @param int $index
+ * @return string
+ */
+ public function getLink($index = 0)
+ {
+ if (!array_key_exists('links', $this->data)) {
+ $this->getLinks();
+ }
+
+ if (isset($this->data['links'][$index])) {
+ return $this->data['links'][$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get all links
+ *
+ * @return array
+ */
+ public function getLinks()
+ {
+ if (array_key_exists('links', $this->data)) {
+ return $this->data['links'];
+ }
+
+ $links = array();
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $list = $this->xpath->query($this->xpathQueryRss . '//link');
+ } else {
+ $list = $this->xpath->query($this->xpathQueryRdf . '//rss:link');
+ }
+
+ if (!$list->length) {
+ $links = $this->getExtension('Atom')->getLinks();
+ } else {
+ foreach ($list as $link) {
+ $links[] = $link->nodeValue;
+ }
+ }
+
+ $this->data['links'] = $links;
+
+ return $this->data['links'];
+ }
+
+ /**
+ * Get all categories
+ *
+ * @return Reader\Collection\Category
+ */
+ public function getCategories()
+ {
+ if (array_key_exists('categories', $this->data)) {
+ return $this->data['categories'];
+ }
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $list = $this->xpath->query($this->xpathQueryRss . '//category');
+ } else {
+ $list = $this->xpath->query($this->xpathQueryRdf . '//rss:category');
+ }
+
+ if ($list->length) {
+ $categoryCollection = new Reader\Collection\Category;
+ foreach ($list as $category) {
+ $categoryCollection[] = array(
+ 'term' => $category->nodeValue,
+ 'scheme' => $category->getAttribute('domain'),
+ 'label' => $category->nodeValue,
+ );
+ }
+ } else {
+ $categoryCollection = $this->getExtension('DublinCore')->getCategories();
+ }
+
+ if (count($categoryCollection) == 0) {
+ $categoryCollection = $this->getExtension('Atom')->getCategories();
+ }
+
+ $this->data['categories'] = $categoryCollection;
+
+ return $this->data['categories'];
+ }
+
+ /**
+ * Get a permalink to the entry
+ *
+ * @return string
+ */
+ public function getPermalink()
+ {
+ return $this->getLink(0);
+ }
+
+ /**
+ * Get the entry title
+ *
+ * @return string
+ */
+ public function getTitle()
+ {
+ if (array_key_exists('title', $this->data)) {
+ return $this->data['title'];
+ }
+
+ $title = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10
+ && $this->getType() !== Reader\Reader::TYPE_RSS_090
+ ) {
+ $title = $this->xpath->evaluate('string(' . $this->xpathQueryRss . '/title)');
+ } else {
+ $title = $this->xpath->evaluate('string(' . $this->xpathQueryRdf . '/rss:title)');
+ }
+
+ if (!$title) {
+ $title = $this->getExtension('DublinCore')->getTitle();
+ }
+
+ if (!$title) {
+ $title = $this->getExtension('Atom')->getTitle();
+ }
+
+ if (!$title) {
+ $title = null;
+ }
+
+ $this->data['title'] = $title;
+
+ return $this->data['title'];
+ }
+
+ /**
+ * Get the number of comments/replies for current entry
+ *
+ * @return string|null
+ */
+ public function getCommentCount()
+ {
+ if (array_key_exists('commentcount', $this->data)) {
+ return $this->data['commentcount'];
+ }
+
+ $commentcount = $this->getExtension('Slash')->getCommentCount();
+
+ if (!$commentcount) {
+ $commentcount = $this->getExtension('Thread')->getCommentCount();
+ }
+
+ if (!$commentcount) {
+ $commentcount = $this->getExtension('Atom')->getCommentCount();
+ }
+
+ if (!$commentcount) {
+ $commentcount = null;
+ }
+
+ $this->data['commentcount'] = $commentcount;
+
+ return $this->data['commentcount'];
+ }
+
+ /**
+ * Returns a URI pointing to the HTML page where comments can be made on this entry
+ *
+ * @return string
+ */
+ public function getCommentLink()
+ {
+ if (array_key_exists('commentlink', $this->data)) {
+ return $this->data['commentlink'];
+ }
+
+ $commentlink = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10
+ && $this->getType() !== Reader\Reader::TYPE_RSS_090
+ ) {
+ $commentlink = $this->xpath->evaluate('string(' . $this->xpathQueryRss . '/comments)');
+ }
+
+ if (!$commentlink) {
+ $commentlink = $this->getExtension('Atom')->getCommentLink();
+ }
+
+ if (!$commentlink) {
+ $commentlink = null;
+ }
+
+ $this->data['commentlink'] = $commentlink;
+
+ return $this->data['commentlink'];
+ }
+
+ /**
+ * Returns a URI pointing to a feed of all comments for this entry
+ *
+ * @return string
+ */
+ public function getCommentFeedLink()
+ {
+ if (array_key_exists('commentfeedlink', $this->data)) {
+ return $this->data['commentfeedlink'];
+ }
+
+ $commentfeedlink = $this->getExtension('WellFormedWeb')->getCommentFeedLink();
+
+ if (!$commentfeedlink) {
+ $commentfeedlink = $this->getExtension('Atom')->getCommentFeedLink('rss');
+ }
+
+ if (!$commentfeedlink) {
+ $commentfeedlink = $this->getExtension('Atom')->getCommentFeedLink('rdf');
+ }
+
+ if (!$commentfeedlink) {
+ $commentfeedlink = null;
+ }
+
+ $this->data['commentfeedlink'] = $commentfeedlink;
+
+ return $this->data['commentfeedlink'];
+ }
+
+ /**
+ * Set the XPath query (incl. on all Extensions)
+ *
+ * @param DOMXPath $xpath
+ * @return void
+ */
+ public function setXpath(DOMXPath $xpath)
+ {
+ parent::setXpath($xpath);
+ foreach ($this->extensions as $extension) {
+ $extension->setXpath($this->xpath);
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/BadMethodCallException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/BadMethodCallException.php
new file mode 100644
index 0000000..3994b0c
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/BadMethodCallException.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Exception;
+
+use Zend\Feed\Exception;
+
+class BadMethodCallException
+ extends Exception\BadMethodCallException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/ExceptionInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/ExceptionInterface.php
new file mode 100644
index 0000000..09abac6
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/ExceptionInterface.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Exception;
+
+use Zend\Feed\Exception\ExceptionInterface as Exception;
+
+interface ExceptionInterface extends Exception
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/InvalidArgumentException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000..5860322
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/InvalidArgumentException.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Exception;
+
+use Zend\Feed\Exception;
+
+class InvalidArgumentException
+ extends Exception\InvalidArgumentException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/RuntimeException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/RuntimeException.php
new file mode 100644
index 0000000..f0590fb
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Exception/RuntimeException.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Exception;
+
+use Zend\Feed\Exception;
+
+class RuntimeException
+ extends Exception\RuntimeException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/AbstractEntry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/AbstractEntry.php
new file mode 100644
index 0000000..0f0333b
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/AbstractEntry.php
@@ -0,0 +1,233 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension;
+
+use DOMDocument;
+use DOMElement;
+use DOMXPath;
+use Zend\Feed\Reader;
+
+abstract class AbstractEntry
+{
+ /**
+ * Feed entry data
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * DOM document object
+ *
+ * @var DOMDocument
+ */
+ protected $domDocument = null;
+
+ /**
+ * Entry instance
+ *
+ * @var DOMElement
+ */
+ protected $entry = null;
+
+ /**
+ * Pointer to the current entry
+ *
+ * @var int
+ */
+ protected $entryKey = 0;
+
+ /**
+ * XPath object
+ *
+ * @var DOMXPath
+ */
+ protected $xpath = null;
+
+ /**
+ * XPath query
+ *
+ * @var string
+ */
+ protected $xpathPrefix = '';
+
+ /**
+ * Set the entry DOMElement
+ *
+ * Has side effect of setting the DOMDocument for the entry.
+ *
+ * @param DOMElement $entry
+ * @return AbstractEntry
+ */
+ public function setEntryElement(DOMElement $entry)
+ {
+ $this->entry = $entry;
+ $this->domDocument = $entry->ownerDocument;
+ return $this;
+ }
+
+ /**
+ * Get the entry DOMElement
+ *
+ * @return DOMElement
+ */
+ public function getEntryElement()
+ {
+ return $this->entry;
+ }
+
+ /**
+ * Set the entry key
+ *
+ * @param string $entryKey
+ * @return AbstractEntry
+ */
+ public function setEntryKey($entryKey)
+ {
+ $this->entryKey = $entryKey;
+ return $this;
+ }
+
+ /**
+ * Get the DOM
+ *
+ * @return DOMDocument
+ */
+ public function getDomDocument()
+ {
+ return $this->domDocument;
+ }
+
+ /**
+ * Get the Entry's encoding
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ $assumed = $this->getDomDocument()->encoding;
+ return $assumed;
+ }
+
+ /**
+ * Set the entry type
+ *
+ * Has side effect of setting xpath prefix
+ *
+ * @param string $type
+ * @return AbstractEntry
+ */
+ public function setType($type)
+ {
+ if (null === $type) {
+ $this->data['type'] = null;
+ return $this;
+ }
+
+ $this->data['type'] = $type;
+ if ($type === Reader\Reader::TYPE_RSS_10
+ || $type === Reader\Reader::TYPE_RSS_090
+ ) {
+ $this->setXpathPrefix('//rss:item[' . ($this->entryKey + 1) . ']');
+ return $this;
+ }
+
+ if ($type === Reader\Reader::TYPE_ATOM_10
+ || $type === Reader\Reader::TYPE_ATOM_03
+ ) {
+ $this->setXpathPrefix('//atom:entry[' . ($this->entryKey + 1) . ']');
+ return $this;
+ }
+
+ $this->setXpathPrefix('//item[' . ($this->entryKey + 1) . ']');
+ return $this;
+ }
+
+ /**
+ * Get the entry type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ $type = $this->data['type'];
+ if ($type === null) {
+ $type = Reader\Reader::detectType($this->getEntryElement(), true);
+ $this->setType($type);
+ }
+
+ return $type;
+ }
+
+ /**
+ * Set the XPath query
+ *
+ * @param DOMXPath $xpath
+ * @return AbstractEntry
+ */
+ public function setXpath(DOMXPath $xpath)
+ {
+ $this->xpath = $xpath;
+ $this->registerNamespaces();
+ return $this;
+ }
+
+ /**
+ * Get the XPath query object
+ *
+ * @return DOMXPath
+ */
+ public function getXpath()
+ {
+ if (!$this->xpath) {
+ $this->setXpath(new DOMXPath($this->getDomDocument()));
+ }
+ return $this->xpath;
+ }
+
+ /**
+ * Serialize the entry to an array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Get the XPath prefix
+ *
+ * @return string
+ */
+ public function getXpathPrefix()
+ {
+ return $this->xpathPrefix;
+ }
+
+ /**
+ * Set the XPath prefix
+ *
+ * @param string $prefix
+ * @return AbstractEntry
+ */
+ public function setXpathPrefix($prefix)
+ {
+ $this->xpathPrefix = $prefix;
+ return $this;
+ }
+
+ /**
+ * Register XML namespaces
+ *
+ * @return void
+ */
+ abstract protected function registerNamespaces();
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/AbstractFeed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/AbstractFeed.php
new file mode 100644
index 0000000..7508925
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/AbstractFeed.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension;
+
+use DOMDocument;
+use DOMXPath;
+use Zend\Feed\Reader;
+
+abstract class AbstractFeed
+{
+ /**
+ * Parsed feed data
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * Parsed feed data in the shape of a DOMDocument
+ *
+ * @var DOMDocument
+ */
+ protected $domDocument = null;
+
+ /**
+ * The base XPath query used to retrieve feed data
+ *
+ * @var DOMXPath
+ */
+ protected $xpath = null;
+
+ /**
+ * The XPath prefix
+ *
+ * @var string
+ */
+ protected $xpathPrefix = '';
+
+ /**
+ * Set the DOM document
+ *
+ * @param DOMDocument $dom
+ * @return AbstractFeed
+ */
+ public function setDomDocument(DOMDocument $dom)
+ {
+ $this->domDocument = $dom;
+ return $this;
+ }
+
+ /**
+ * Get the DOM
+ *
+ * @return DOMDocument
+ */
+ public function getDomDocument()
+ {
+ return $this->domDocument;
+ }
+
+ /**
+ * Get the Feed's encoding
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ $assumed = $this->getDomDocument()->encoding;
+ return $assumed;
+ }
+
+ /**
+ * Set the feed type
+ *
+ * @param string $type
+ * @return AbstractFeed
+ */
+ public function setType($type)
+ {
+ $this->data['type'] = $type;
+ return $this;
+ }
+
+ /**
+ * Get the feed type
+ *
+ * If null, it will attempt to autodetect the type.
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ $type = $this->data['type'];
+ if (null === $type) {
+ $type = Reader\Reader::detectType($this->getDomDocument());
+ $this->setType($type);
+ }
+ return $type;
+ }
+
+
+ /**
+ * Return the feed as an array
+ *
+ * @return array
+ */
+ public function toArray() // untested
+ {
+ return $this->data;
+ }
+
+ /**
+ * Set the XPath query
+ *
+ * @param DOMXPath $xpath
+ * @return AbstractEntry
+ */
+ public function setXpath(DOMXPath $xpath = null)
+ {
+ if (null === $xpath) {
+ $this->xpath = null;
+ return $this;
+ }
+
+ $this->xpath = $xpath;
+ $this->registerNamespaces();
+ return $this;
+ }
+
+ /**
+ * Get the DOMXPath object
+ *
+ * @return string
+ */
+ public function getXpath()
+ {
+ if (null === $this->xpath) {
+ $this->setXpath(new DOMXPath($this->getDomDocument()));
+ }
+
+ return $this->xpath;
+ }
+
+ /**
+ * Get the XPath prefix
+ *
+ * @return string
+ */
+ public function getXpathPrefix()
+ {
+ return $this->xpathPrefix;
+ }
+
+ /**
+ * Set the XPath prefix
+ *
+ * @param string $prefix
+ * @return void
+ */
+ public function setXpathPrefix($prefix)
+ {
+ $this->xpathPrefix = $prefix;
+ }
+
+ /**
+ * Register the default namespaces for the current feed format
+ */
+ abstract protected function registerNamespaces();
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Atom/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Atom/Entry.php
new file mode 100644
index 0000000..d68577c
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Atom/Entry.php
@@ -0,0 +1,628 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\Atom;
+
+use DateTime;
+use DOMDocument;
+use DOMElement;
+use stdClass;
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Collection;
+use Zend\Feed\Reader\Extension;
+use Zend\Feed\Uri;
+
+class Entry extends Extension\AbstractEntry
+{
+ /**
+ * Get the specified author
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getAuthor($index = 0)
+ {
+ $authors = $this->getAuthors();
+
+ if (isset($authors[$index])) {
+ return $authors[$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return Collection\Author
+ */
+ public function getAuthors()
+ {
+ if (array_key_exists('authors', $this->data)) {
+ return $this->data['authors'];
+ }
+
+ $authors = array();
+ $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom:author');
+
+ if (!$list->length) {
+ /**
+ * TODO: Limit query to feed level els only!
+ */
+ $list = $this->getXpath()->query('//atom:author');
+ }
+
+ if ($list->length) {
+ foreach ($list as $author) {
+ $author = $this->getAuthorFromElement($author);
+ if (!empty($author)) {
+ $authors[] = $author;
+ }
+ }
+ }
+
+ if (count($authors) == 0) {
+ $authors = new Collection\Author();
+ } else {
+ $authors = new Collection\Author(
+ Reader\Reader::arrayUnique($authors)
+ );
+ }
+
+ $this->data['authors'] = $authors;
+ return $this->data['authors'];
+ }
+
+ /**
+ * Get the entry content
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ if (array_key_exists('content', $this->data)) {
+ return $this->data['content'];
+ }
+
+ $content = null;
+
+ $el = $this->getXpath()->query($this->getXpathPrefix() . '/atom:content');
+ if ($el->length > 0) {
+ $el = $el->item(0);
+ $type = $el->getAttribute('type');
+ switch ($type) {
+ case '':
+ case 'text':
+ case 'text/plain':
+ case 'html':
+ case 'text/html':
+ $content = $el->nodeValue;
+ break;
+ case 'xhtml':
+ $this->getXpath()->registerNamespace('xhtml', 'http://www.w3.org/1999/xhtml');
+ $xhtml = $this->getXpath()->query(
+ $this->getXpathPrefix() . '/atom:content/xhtml:div'
+ )->item(0);
+ $d = new DOMDocument('1.0', $this->getEncoding());
+ $xhtmls = $d->importNode($xhtml, true);
+ $d->appendChild($xhtmls);
+ $content = $this->collectXhtml(
+ $d->saveXML(),
+ $d->lookupPrefix('http://www.w3.org/1999/xhtml')
+ );
+ break;
+ }
+ }
+
+ if (!$content) {
+ $content = $this->getDescription();
+ }
+
+ $this->data['content'] = trim($content);
+
+ return $this->data['content'];
+ }
+
+ /**
+ * Parse out XHTML to remove the namespacing
+ *
+ * @param $xhtml
+ * @param $prefix
+ * @return mixed
+ */
+ protected function collectXhtml($xhtml, $prefix)
+ {
+ if (!empty($prefix)) $prefix = $prefix . ':';
+ $matches = array(
+ "/<\?xml[^<]*>[^<]*<" . $prefix . "div[^<]*/",
+ "/<\/" . $prefix . "div>\s*$/"
+ );
+ $xhtml = preg_replace($matches, '', $xhtml);
+ if (!empty($prefix)) {
+ $xhtml = preg_replace("/(<[\/]?)" . $prefix . "([a-zA-Z]+)/", '$1$2', $xhtml);
+ }
+ return $xhtml;
+ }
+
+ /**
+ * Get the entry creation date
+ *
+ * @return string
+ */
+ public function getDateCreated()
+ {
+ if (array_key_exists('datecreated', $this->data)) {
+ return $this->data['datecreated'];
+ }
+
+ $date = null;
+
+ if ($this->getAtomType() === Reader\Reader::TYPE_ATOM_03) {
+ $dateCreated = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:created)');
+ } else {
+ $dateCreated = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:published)');
+ }
+
+ if ($dateCreated) {
+ $date = new DateTime($dateCreated);
+ }
+
+ $this->data['datecreated'] = $date;
+
+ return $this->data['datecreated'];
+ }
+
+ /**
+ * Get the entry modification date
+ *
+ * @return string
+ */
+ public function getDateModified()
+ {
+ if (array_key_exists('datemodified', $this->data)) {
+ return $this->data['datemodified'];
+ }
+
+ $date = null;
+
+ if ($this->getAtomType() === Reader\Reader::TYPE_ATOM_03) {
+ $dateModified = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:modified)');
+ } else {
+ $dateModified = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:updated)');
+ }
+
+ if ($dateModified) {
+ $date = new DateTime($dateModified);
+ }
+
+ $this->data['datemodified'] = $date;
+
+ return $this->data['datemodified'];
+ }
+
+ /**
+ * Get the entry description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ if (array_key_exists('description', $this->data)) {
+ return $this->data['description'];
+ }
+
+ $description = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:summary)');
+
+ if (!$description) {
+ $description = null;
+ }
+
+ $this->data['description'] = $description;
+
+ return $this->data['description'];
+ }
+
+ /**
+ * Get the entry enclosure
+ *
+ * @return string
+ */
+ public function getEnclosure()
+ {
+ if (array_key_exists('enclosure', $this->data)) {
+ return $this->data['enclosure'];
+ }
+
+ $enclosure = null;
+
+ $nodeList = $this->getXpath()->query($this->getXpathPrefix() . '/atom:link[@rel="enclosure"]');
+
+ if ($nodeList->length > 0) {
+ $enclosure = new stdClass();
+ $enclosure->url = $nodeList->item(0)->getAttribute('href');
+ $enclosure->length = $nodeList->item(0)->getAttribute('length');
+ $enclosure->type = $nodeList->item(0)->getAttribute('type');
+ }
+
+ $this->data['enclosure'] = $enclosure;
+
+ return $this->data['enclosure'];
+ }
+
+ /**
+ * Get the entry ID
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ if (array_key_exists('id', $this->data)) {
+ return $this->data['id'];
+ }
+
+ $id = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:id)');
+
+ if (!$id) {
+ if ($this->getPermalink()) {
+ $id = $this->getPermalink();
+ } elseif ($this->getTitle()) {
+ $id = $this->getTitle();
+ } else {
+ $id = null;
+ }
+ }
+
+ $this->data['id'] = $id;
+
+ return $this->data['id'];
+ }
+
+ /**
+ * Get the base URI of the feed (if set).
+ *
+ * @return string|null
+ */
+ public function getBaseUrl()
+ {
+ if (array_key_exists('baseUrl', $this->data)) {
+ return $this->data['baseUrl'];
+ }
+
+ $baseUrl = $this->getXpath()->evaluate('string('
+ . $this->getXpathPrefix() . '/@xml:base[1]'
+ . ')');
+
+ if (!$baseUrl) {
+ $baseUrl = $this->getXpath()->evaluate('string(//@xml:base[1])');
+ }
+
+ if (!$baseUrl) {
+ $baseUrl = null;
+ }
+
+ $this->data['baseUrl'] = $baseUrl;
+
+ return $this->data['baseUrl'];
+ }
+
+ /**
+ * Get a specific link
+ *
+ * @param int $index
+ * @return string
+ */
+ public function getLink($index = 0)
+ {
+ if (!array_key_exists('links', $this->data)) {
+ $this->getLinks();
+ }
+
+ if (isset($this->data['links'][$index])) {
+ return $this->data['links'][$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get all links
+ *
+ * @return array
+ */
+ public function getLinks()
+ {
+ if (array_key_exists('links', $this->data)) {
+ return $this->data['links'];
+ }
+
+ $links = array();
+
+ $list = $this->getXpath()->query(
+ $this->getXpathPrefix() . '//atom:link[@rel="alternate"]/@href' . '|' .
+ $this->getXpathPrefix() . '//atom:link[not(@rel)]/@href'
+ );
+
+ if ($list->length) {
+ foreach ($list as $link) {
+ $links[] = $this->absolutiseUri($link->value);
+ }
+ }
+
+ $this->data['links'] = $links;
+
+ return $this->data['links'];
+ }
+
+ /**
+ * Get a permalink to the entry
+ *
+ * @return string
+ */
+ public function getPermalink()
+ {
+ return $this->getLink(0);
+ }
+
+ /**
+ * Get the entry title
+ *
+ * @return string
+ */
+ public function getTitle()
+ {
+ if (array_key_exists('title', $this->data)) {
+ return $this->data['title'];
+ }
+
+ $title = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:title)');
+
+ if (!$title) {
+ $title = null;
+ }
+
+ $this->data['title'] = $title;
+
+ return $this->data['title'];
+ }
+
+ /**
+ * Get the number of comments/replies for current entry
+ *
+ * @return int
+ */
+ public function getCommentCount()
+ {
+ if (array_key_exists('commentcount', $this->data)) {
+ return $this->data['commentcount'];
+ }
+
+ $count = null;
+
+ $this->getXpath()->registerNamespace('thread10', 'http://purl.org/syndication/thread/1.0');
+ $list = $this->getXpath()->query(
+ $this->getXpathPrefix() . '//atom:link[@rel="replies"]/@thread10:count'
+ );
+
+ if ($list->length) {
+ $count = $list->item(0)->value;
+ }
+
+ $this->data['commentcount'] = $count;
+
+ return $this->data['commentcount'];
+ }
+
+ /**
+ * Returns a URI pointing to the HTML page where comments can be made on this entry
+ *
+ * @return string
+ */
+ public function getCommentLink()
+ {
+ if (array_key_exists('commentlink', $this->data)) {
+ return $this->data['commentlink'];
+ }
+
+ $link = null;
+
+ $list = $this->getXpath()->query(
+ $this->getXpathPrefix() . '//atom:link[@rel="replies" and @type="text/html"]/@href'
+ );
+
+ if ($list->length) {
+ $link = $list->item(0)->value;
+ $link = $this->absolutiseUri($link);
+ }
+
+ $this->data['commentlink'] = $link;
+
+ return $this->data['commentlink'];
+ }
+
+ /**
+ * Returns a URI pointing to a feed of all comments for this entry
+ *
+ * @param string $type
+ * @return string
+ */
+ public function getCommentFeedLink($type = 'atom')
+ {
+ if (array_key_exists('commentfeedlink', $this->data)) {
+ return $this->data['commentfeedlink'];
+ }
+
+ $link = null;
+
+ $list = $this->getXpath()->query(
+ $this->getXpathPrefix() . '//atom:link[@rel="replies" and @type="application/' . $type.'+xml"]/@href'
+ );
+
+ if ($list->length) {
+ $link = $list->item(0)->value;
+ $link = $this->absolutiseUri($link);
+ }
+
+ $this->data['commentfeedlink'] = $link;
+
+ return $this->data['commentfeedlink'];
+ }
+
+ /**
+ * Get all categories
+ *
+ * @return Collection\Category
+ */
+ public function getCategories()
+ {
+ if (array_key_exists('categories', $this->data)) {
+ return $this->data['categories'];
+ }
+
+ if ($this->getAtomType() == Reader\Reader::TYPE_ATOM_10) {
+ $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom:category');
+ } else {
+ /**
+ * Since Atom 0.3 did not support categories, it would have used the
+ * Dublin Core extension. However there is a small possibility Atom 0.3
+ * may have been retrofitted to use Atom 1.0 instead.
+ */
+ $this->getXpath()->registerNamespace('atom10', Reader\Reader::NAMESPACE_ATOM_10);
+ $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom10:category');
+ }
+
+ if ($list->length) {
+ $categoryCollection = new Collection\Category;
+ foreach ($list as $category) {
+ $categoryCollection[] = array(
+ 'term' => $category->getAttribute('term'),
+ 'scheme' => $category->getAttribute('scheme'),
+ 'label' => $category->getAttribute('label')
+ );
+ }
+ } else {
+ return new Collection\Category;
+ }
+
+ $this->data['categories'] = $categoryCollection;
+
+ return $this->data['categories'];
+ }
+
+ /**
+ * Get source feed metadata from the entry
+ *
+ * @return Reader\Feed\Atom\Source|null
+ */
+ public function getSource()
+ {
+ if (array_key_exists('source', $this->data)) {
+ return $this->data['source'];
+ }
+
+ $source = null;
+ // TODO: Investigate why _getAtomType() fails here. Is it even needed?
+ if ($this->getType() == Reader\Reader::TYPE_ATOM_10) {
+ $list = $this->getXpath()->query($this->getXpathPrefix() . '/atom:source[1]');
+ if ($list->length) {
+ $element = $list->item(0);
+ $source = new Reader\Feed\Atom\Source($element, $this->getXpathPrefix());
+ }
+ }
+
+ $this->data['source'] = $source;
+ return $this->data['source'];
+ }
+
+ /**
+ * Attempt to absolutise the URI, i.e. if a relative URI apply the
+ * xml:base value as a prefix to turn into an absolute URI.
+ *
+ * @param $link
+ * @return string
+ */
+ protected function absolutiseUri($link)
+ {
+ if (!Uri::factory($link)->isAbsolute()) {
+ if ($this->getBaseUrl() !== null) {
+ $link = $this->getBaseUrl() . $link;
+ if (!Uri::factory($link)->isValid()) {
+ $link = null;
+ }
+ }
+ }
+ return $link;
+ }
+
+ /**
+ * Get an author entry
+ *
+ * @param DOMElement $element
+ * @return string
+ */
+ protected function getAuthorFromElement(DOMElement $element)
+ {
+ $author = array();
+
+ $emailNode = $element->getElementsByTagName('email');
+ $nameNode = $element->getElementsByTagName('name');
+ $uriNode = $element->getElementsByTagName('uri');
+
+ if ($emailNode->length && strlen($emailNode->item(0)->nodeValue) > 0) {
+ $author['email'] = $emailNode->item(0)->nodeValue;
+ }
+
+ if ($nameNode->length && strlen($nameNode->item(0)->nodeValue) > 0) {
+ $author['name'] = $nameNode->item(0)->nodeValue;
+ }
+
+ if ($uriNode->length && strlen($uriNode->item(0)->nodeValue) > 0) {
+ $author['uri'] = $uriNode->item(0)->nodeValue;
+ }
+
+ if (empty($author)) {
+ return null;
+ }
+ return $author;
+ }
+
+ /**
+ * Register the default namespaces for the current feed format
+ */
+ protected function registerNamespaces()
+ {
+ switch ($this->getAtomType()) {
+ case Reader\Reader::TYPE_ATOM_03:
+ $this->getXpath()->registerNamespace('atom', Reader\Reader::NAMESPACE_ATOM_03);
+ break;
+ default:
+ $this->getXpath()->registerNamespace('atom', Reader\Reader::NAMESPACE_ATOM_10);
+ break;
+ }
+ }
+
+ /**
+ * Detect the presence of any Atom namespaces in use
+ *
+ * @return string
+ */
+ protected function getAtomType()
+ {
+ $dom = $this->getDomDocument();
+ $prefixAtom03 = $dom->lookupPrefix(Reader\Reader::NAMESPACE_ATOM_03);
+ $prefixAtom10 = $dom->lookupPrefix(Reader\Reader::NAMESPACE_ATOM_10);
+ if ($dom->isDefaultNamespace(Reader\Reader::NAMESPACE_ATOM_03)
+ || !empty($prefixAtom03)) {
+ return Reader\Reader::TYPE_ATOM_03;
+ }
+ if ($dom->isDefaultNamespace(Reader\Reader::NAMESPACE_ATOM_10)
+ || !empty($prefixAtom10)) {
+ return Reader\Reader::TYPE_ATOM_10;
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Atom/Feed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Atom/Feed.php
new file mode 100644
index 0000000..83e9cca
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Atom/Feed.php
@@ -0,0 +1,536 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\Atom;
+
+use DateTime;
+use DOMElement;
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Collection;
+use Zend\Feed\Reader\Extension;
+use Zend\Feed\Uri;
+
+class Feed extends Extension\AbstractFeed
+{
+ /**
+ * Get a single author
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getAuthor($index = 0)
+ {
+ $authors = $this->getAuthors();
+
+ if (isset($authors[$index])) {
+ return $authors[$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return Collection\Author
+ */
+ public function getAuthors()
+ {
+ if (array_key_exists('authors', $this->data)) {
+ return $this->data['authors'];
+ }
+
+ $list = $this->xpath->query('//atom:author');
+
+ $authors = array();
+
+ if ($list->length) {
+ foreach ($list as $author) {
+ $author = $this->getAuthorFromElement($author);
+ if (!empty($author)) {
+ $authors[] = $author;
+ }
+ }
+ }
+
+ if (count($authors) == 0) {
+ $authors = new Collection\Author();
+ } else {
+ $authors = new Collection\Author(
+ Reader\Reader::arrayUnique($authors)
+ );
+ }
+
+ $this->data['authors'] = $authors;
+
+ return $this->data['authors'];
+ }
+
+ /**
+ * Get the copyright entry
+ *
+ * @return string|null
+ */
+ public function getCopyright()
+ {
+ if (array_key_exists('copyright', $this->data)) {
+ return $this->data['copyright'];
+ }
+
+ $copyright = null;
+
+ if ($this->getType() === Reader\Reader::TYPE_ATOM_03) {
+ $copyright = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:copyright)');
+ } else {
+ $copyright = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:rights)');
+ }
+
+ if (!$copyright) {
+ $copyright = null;
+ }
+
+ $this->data['copyright'] = $copyright;
+
+ return $this->data['copyright'];
+ }
+
+ /**
+ * Get the feed creation date
+ *
+ * @return DateTime|null
+ */
+ public function getDateCreated()
+ {
+ if (array_key_exists('datecreated', $this->data)) {
+ return $this->data['datecreated'];
+ }
+
+ $date = null;
+
+ if ($this->getType() === Reader\Reader::TYPE_ATOM_03) {
+ $dateCreated = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:created)');
+ } else {
+ $dateCreated = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:published)');
+ }
+
+ if ($dateCreated) {
+ $date = new DateTime($dateCreated);
+ }
+
+ $this->data['datecreated'] = $date;
+
+ return $this->data['datecreated'];
+ }
+
+ /**
+ * Get the feed modification date
+ *
+ * @return DateTime|null
+ */
+ public function getDateModified()
+ {
+ if (array_key_exists('datemodified', $this->data)) {
+ return $this->data['datemodified'];
+ }
+
+ $date = null;
+
+ if ($this->getType() === Reader\Reader::TYPE_ATOM_03) {
+ $dateModified = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:modified)');
+ } else {
+ $dateModified = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:updated)');
+ }
+
+ if ($dateModified) {
+ $date = new DateTime($dateModified);
+ }
+
+ $this->data['datemodified'] = $date;
+
+ return $this->data['datemodified'];
+ }
+
+ /**
+ * Get the feed description
+ *
+ * @return string|null
+ */
+ public function getDescription()
+ {
+ if (array_key_exists('description', $this->data)) {
+ return $this->data['description'];
+ }
+
+ $description = null;
+
+ if ($this->getType() === Reader\Reader::TYPE_ATOM_03) {
+ $description = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:tagline)');
+ } else {
+ $description = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:subtitle)');
+ }
+
+ if (!$description) {
+ $description = null;
+ }
+
+ $this->data['description'] = $description;
+
+ return $this->data['description'];
+ }
+
+ /**
+ * Get the feed generator entry
+ *
+ * @return string|null
+ */
+ public function getGenerator()
+ {
+ if (array_key_exists('generator', $this->data)) {
+ return $this->data['generator'];
+ }
+ // TODO: Add uri support
+ $generator = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:generator)');
+
+ if (!$generator) {
+ $generator = null;
+ }
+
+ $this->data['generator'] = $generator;
+
+ return $this->data['generator'];
+ }
+
+ /**
+ * Get the feed ID
+ *
+ * @return string|null
+ */
+ public function getId()
+ {
+ if (array_key_exists('id', $this->data)) {
+ return $this->data['id'];
+ }
+
+ $id = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:id)');
+
+ if (!$id) {
+ if ($this->getLink()) {
+ $id = $this->getLink();
+ } elseif ($this->getTitle()) {
+ $id = $this->getTitle();
+ } else {
+ $id = null;
+ }
+ }
+
+ $this->data['id'] = $id;
+
+ return $this->data['id'];
+ }
+
+ /**
+ * Get the feed language
+ *
+ * @return string|null
+ */
+ public function getLanguage()
+ {
+ if (array_key_exists('language', $this->data)) {
+ return $this->data['language'];
+ }
+
+ $language = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:lang)');
+
+ if (!$language) {
+ $language = $this->xpath->evaluate('string(//@xml:lang[1])');
+ }
+
+ if (!$language) {
+ $language = null;
+ }
+
+ $this->data['language'] = $language;
+
+ return $this->data['language'];
+ }
+
+ /**
+ * Get the feed image
+ *
+ * @return array|null
+ */
+ public function getImage()
+ {
+ if (array_key_exists('image', $this->data)) {
+ return $this->data['image'];
+ }
+
+ $imageUrl = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:logo)');
+
+ if (!$imageUrl) {
+ $image = null;
+ } else {
+ $image = array('uri' => $imageUrl);
+ }
+
+ $this->data['image'] = $image;
+
+ return $this->data['image'];
+ }
+
+ /**
+ * Get the base URI of the feed (if set).
+ *
+ * @return string|null
+ */
+ public function getBaseUrl()
+ {
+ if (array_key_exists('baseUrl', $this->data)) {
+ return $this->data['baseUrl'];
+ }
+
+ $baseUrl = $this->xpath->evaluate('string(//@xml:base[1])');
+
+ if (!$baseUrl) {
+ $baseUrl = null;
+ }
+ $this->data['baseUrl'] = $baseUrl;
+
+ return $this->data['baseUrl'];
+ }
+
+ /**
+ * Get a link to the source website
+ *
+ * @return string|null
+ */
+ public function getLink()
+ {
+ if (array_key_exists('link', $this->data)) {
+ return $this->data['link'];
+ }
+
+ $link = null;
+
+ $list = $this->xpath->query(
+ $this->getXpathPrefix() . '/atom:link[@rel="alternate"]/@href' . '|' .
+ $this->getXpathPrefix() . '/atom:link[not(@rel)]/@href'
+ );
+
+ if ($list->length) {
+ $link = $list->item(0)->nodeValue;
+ $link = $this->absolutiseUri($link);
+ }
+
+ $this->data['link'] = $link;
+
+ return $this->data['link'];
+ }
+
+ /**
+ * Get a link to the feed's XML Url
+ *
+ * @return string|null
+ */
+ public function getFeedLink()
+ {
+ if (array_key_exists('feedlink', $this->data)) {
+ return $this->data['feedlink'];
+ }
+
+ $link = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:link[@rel="self"]/@href)');
+
+ $link = $this->absolutiseUri($link);
+
+ $this->data['feedlink'] = $link;
+
+ return $this->data['feedlink'];
+ }
+
+ /**
+ * Get an array of any supported Pusubhubbub endpoints
+ *
+ * @return array|null
+ */
+ public function getHubs()
+ {
+ if (array_key_exists('hubs', $this->data)) {
+ return $this->data['hubs'];
+ }
+ $hubs = array();
+
+ $list = $this->xpath->query($this->getXpathPrefix()
+ . '//atom:link[@rel="hub"]/@href');
+
+ if ($list->length) {
+ foreach ($list as $uri) {
+ $hubs[] = $this->absolutiseUri($uri->nodeValue);
+ }
+ } else {
+ $hubs = null;
+ }
+
+ $this->data['hubs'] = $hubs;
+
+ return $this->data['hubs'];
+ }
+
+ /**
+ * Get the feed title
+ *
+ * @return string|null
+ */
+ public function getTitle()
+ {
+ if (array_key_exists('title', $this->data)) {
+ return $this->data['title'];
+ }
+
+ $title = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:title)');
+
+ if (!$title) {
+ $title = null;
+ }
+
+ $this->data['title'] = $title;
+
+ return $this->data['title'];
+ }
+
+ /**
+ * Get all categories
+ *
+ * @return Collection\Category
+ */
+ public function getCategories()
+ {
+ if (array_key_exists('categories', $this->data)) {
+ return $this->data['categories'];
+ }
+
+ if ($this->getType() == Reader\Reader::TYPE_ATOM_10) {
+ $list = $this->xpath->query($this->getXpathPrefix() . '/atom:category');
+ } else {
+ /**
+ * Since Atom 0.3 did not support categories, it would have used the
+ * Dublin Core extension. However there is a small possibility Atom 0.3
+ * may have been retrofittied to use Atom 1.0 instead.
+ */
+ $this->xpath->registerNamespace('atom10', Reader\Reader::NAMESPACE_ATOM_10);
+ $list = $this->xpath->query($this->getXpathPrefix() . '/atom10:category');
+ }
+
+ if ($list->length) {
+ $categoryCollection = new Collection\Category;
+ foreach ($list as $category) {
+ $categoryCollection[] = array(
+ 'term' => $category->getAttribute('term'),
+ 'scheme' => $category->getAttribute('scheme'),
+ 'label' => $category->getAttribute('label')
+ );
+ }
+ } else {
+ return new Collection\Category;
+ }
+
+ $this->data['categories'] = $categoryCollection;
+
+ return $this->data['categories'];
+ }
+
+ /**
+ * Get an author entry in RSS format
+ *
+ * @param DOMElement $element
+ * @return string
+ */
+ protected function getAuthorFromElement(DOMElement $element)
+ {
+ $author = array();
+
+ $emailNode = $element->getElementsByTagName('email');
+ $nameNode = $element->getElementsByTagName('name');
+ $uriNode = $element->getElementsByTagName('uri');
+
+ if ($emailNode->length && strlen($emailNode->item(0)->nodeValue) > 0) {
+ $author['email'] = $emailNode->item(0)->nodeValue;
+ }
+
+ if ($nameNode->length && strlen($nameNode->item(0)->nodeValue) > 0) {
+ $author['name'] = $nameNode->item(0)->nodeValue;
+ }
+
+ if ($uriNode->length && strlen($uriNode->item(0)->nodeValue) > 0) {
+ $author['uri'] = $uriNode->item(0)->nodeValue;
+ }
+
+ if (empty($author)) {
+ return null;
+ }
+ return $author;
+ }
+
+ /**
+ * Attempt to absolutise the URI, i.e. if a relative URI apply the
+ * xml:base value as a prefix to turn into an absolute URI.
+ */
+ protected function absolutiseUri($link)
+ {
+ if (!Uri::factory($link)->isAbsolute()) {
+ if ($this->getBaseUrl() !== null) {
+ $link = $this->getBaseUrl() . $link;
+ if (!Uri::factory($link)->isValid()) {
+ $link = null;
+ }
+ }
+ }
+ return $link;
+ }
+
+ /**
+ * Register the default namespaces for the current feed format
+ */
+ protected function registerNamespaces()
+ {
+ if ($this->getType() == Reader\Reader::TYPE_ATOM_10
+ || $this->getType() == Reader\Reader::TYPE_ATOM_03
+ ) {
+ return; // pre-registered at Feed level
+ }
+ $atomDetected = $this->getAtomType();
+ switch ($atomDetected) {
+ case Reader\Reader::TYPE_ATOM_03:
+ $this->xpath->registerNamespace('atom', Reader\Reader::NAMESPACE_ATOM_03);
+ break;
+ default:
+ $this->xpath->registerNamespace('atom', Reader\Reader::NAMESPACE_ATOM_10);
+ break;
+ }
+ }
+
+ /**
+ * Detect the presence of any Atom namespaces in use
+ */
+ protected function getAtomType()
+ {
+ $dom = $this->getDomDocument();
+ $prefixAtom03 = $dom->lookupPrefix(Reader\Reader::NAMESPACE_ATOM_03);
+ $prefixAtom10 = $dom->lookupPrefix(Reader\Reader::NAMESPACE_ATOM_10);
+ if ($dom->isDefaultNamespace(Reader\Reader::NAMESPACE_ATOM_10)
+ || !empty($prefixAtom10)
+ ) {
+ return Reader\Reader::TYPE_ATOM_10;
+ }
+ if ($dom->isDefaultNamespace(Reader\Reader::NAMESPACE_ATOM_03)
+ || !empty($prefixAtom03)
+ ) {
+ return Reader\Reader::TYPE_ATOM_03;
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Content/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Content/Entry.php
new file mode 100644
index 0000000..88fd850
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Content/Entry.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\Content;
+
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Extension;
+
+class Entry extends Extension\AbstractEntry
+{
+
+ public function getContent()
+ {
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10
+ && $this->getType() !== Reader\Reader::TYPE_RSS_090
+ ) {
+ $content = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/content:encoded)');
+ } else {
+ $content = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/content:encoded)');
+ }
+ return $content;
+ }
+
+ /**
+ * Register RSS Content Module namespace
+ */
+ protected function registerNamespaces()
+ {
+ $this->xpath->registerNamespace('content', 'http://purl.org/rss/1.0/modules/content/');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php
new file mode 100644
index 0000000..0352102
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\CreativeCommons;
+
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Extension;
+
+class Entry extends Extension\AbstractEntry
+{
+ /**
+ * Get the entry license
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getLicense($index = 0)
+ {
+ $licenses = $this->getLicenses();
+
+ if (isset($licenses[$index])) {
+ return $licenses[$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the entry licenses
+ *
+ * @return array
+ */
+ public function getLicenses()
+ {
+ $name = 'licenses';
+ if (array_key_exists($name, $this->data)) {
+ return $this->data[$name];
+ }
+
+ $licenses = array();
+ $list = $this->xpath->evaluate($this->getXpathPrefix() . '//cc:license');
+
+ if ($list->length) {
+ foreach ($list as $license) {
+ $licenses[] = $license->nodeValue;
+ }
+
+ $licenses = array_unique($licenses);
+ } else {
+ $cc = new Feed();
+ $licenses = $cc->getLicenses();
+ }
+
+ $this->data[$name] = $licenses;
+
+ return $this->data[$name];
+ }
+
+ /**
+ * Register Creative Commons namespaces
+ *
+ */
+ protected function registerNamespaces()
+ {
+ $this->xpath->registerNamespace('cc', 'http://backend.userland.com/creativeCommonsRssModule');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php
new file mode 100644
index 0000000..d2a5049
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\CreativeCommons;
+
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Extension;
+
+class Feed extends Extension\AbstractFeed
+{
+ /**
+ * Get the entry license
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getLicense($index = 0)
+ {
+ $licenses = $this->getLicenses();
+
+ if (isset($licenses[$index])) {
+ return $licenses[$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the entry licenses
+ *
+ * @return array
+ */
+ public function getLicenses()
+ {
+ $name = 'licenses';
+ if (array_key_exists($name, $this->data)) {
+ return $this->data[$name];
+ }
+
+ $licenses = array();
+ $list = $this->xpath->evaluate('channel/cc:license');
+
+ if ($list->length) {
+ foreach ($list as $license) {
+ $licenses[] = $license->nodeValue;
+ }
+
+ $licenses = array_unique($licenses);
+ }
+
+ $this->data[$name] = $licenses;
+
+ return $this->data[$name];
+ }
+
+ /**
+ * Register Creative Commons namespaces
+ *
+ * @return void
+ */
+ protected function registerNamespaces()
+ {
+ $this->xpath->registerNamespace('cc', 'http://backend.userland.com/creativeCommonsRssModule');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/DublinCore/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/DublinCore/Entry.php
new file mode 100644
index 0000000..7ec5304
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/DublinCore/Entry.php
@@ -0,0 +1,238 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\DublinCore;
+
+use DateTime;
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Collection;
+use Zend\Feed\Reader\Extension;
+
+class Entry extends Extension\AbstractEntry
+{
+ /**
+ * Get an author entry
+ *
+ * @param int $index
+ * @return string
+ */
+ public function getAuthor($index = 0)
+ {
+ $authors = $this->getAuthors();
+
+ if (isset($authors[$index])) {
+ return $authors[$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return array
+ */
+ public function getAuthors()
+ {
+ if (array_key_exists('authors', $this->data)) {
+ return $this->data['authors'];
+ }
+
+ $authors = array();
+ $list = $this->getXpath()->evaluate($this->getXpathPrefix() . '//dc11:creator');
+
+ if (!$list->length) {
+ $list = $this->getXpath()->evaluate($this->getXpathPrefix() . '//dc10:creator');
+ }
+ if (!$list->length) {
+ $list = $this->getXpath()->evaluate($this->getXpathPrefix() . '//dc11:publisher');
+
+ if (!$list->length) {
+ $list = $this->getXpath()->evaluate($this->getXpathPrefix() . '//dc10:publisher');
+ }
+ }
+
+ if ($list->length) {
+ foreach ($list as $author) {
+ $authors[] = array(
+ 'name' => $author->nodeValue
+ );
+ }
+ $authors = new Collection\Author(
+ Reader\Reader::arrayUnique($authors)
+ );
+ } else {
+ $authors = null;
+ }
+
+ $this->data['authors'] = $authors;
+
+ return $this->data['authors'];
+ }
+
+ /**
+ * Get categories (subjects under DC)
+ *
+ * @return Collection\Category
+ */
+ public function getCategories()
+ {
+ if (array_key_exists('categories', $this->data)) {
+ return $this->data['categories'];
+ }
+
+ $list = $this->getXpath()->evaluate($this->getXpathPrefix() . '//dc11:subject');
+
+ if (!$list->length) {
+ $list = $this->getXpath()->evaluate($this->getXpathPrefix() . '//dc10:subject');
+ }
+
+ if ($list->length) {
+ $categoryCollection = new Collection\Category;
+ foreach ($list as $category) {
+ $categoryCollection[] = array(
+ 'term' => $category->nodeValue,
+ 'scheme' => null,
+ 'label' => $category->nodeValue,
+ );
+ }
+ } else {
+ $categoryCollection = new Collection\Category;
+ }
+
+ $this->data['categories'] = $categoryCollection;
+ return $this->data['categories'];
+ }
+
+
+ /**
+ * Get the entry content
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ return $this->getDescription();
+ }
+
+ /**
+ * Get the entry description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ if (array_key_exists('description', $this->data)) {
+ return $this->data['description'];
+ }
+
+ $description = null;
+ $description = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:description)');
+
+ if (!$description) {
+ $description = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc10:description)');
+ }
+
+ if (!$description) {
+ $description = null;
+ }
+
+ $this->data['description'] = $description;
+
+ return $this->data['description'];
+ }
+
+ /**
+ * Get the entry ID
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ if (array_key_exists('id', $this->data)) {
+ return $this->data['id'];
+ }
+
+ $id = null;
+ $id = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:identifier)');
+
+ if (!$id) {
+ $id = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc10:identifier)');
+ }
+
+ $this->data['id'] = $id;
+
+ return $this->data['id'];
+ }
+
+ /**
+ * Get the entry title
+ *
+ * @return string
+ */
+ public function getTitle()
+ {
+ if (array_key_exists('title', $this->data)) {
+ return $this->data['title'];
+ }
+
+ $title = null;
+ $title = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:title)');
+
+ if (!$title) {
+ $title = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc10:title)');
+ }
+
+ if (!$title) {
+ $title = null;
+ }
+
+ $this->data['title'] = $title;
+
+ return $this->data['title'];
+ }
+
+ /**
+ *
+ *
+ * @return DateTime|null
+ */
+ public function getDate()
+ {
+ if (array_key_exists('date', $this->data)) {
+ return $this->data['date'];
+ }
+
+ $d = null;
+ $date = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:date)');
+
+ if (!$date) {
+ $date = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc10:date)');
+ }
+
+ if ($date) {
+ $d = new DateTime($date);
+ }
+
+ $this->data['date'] = $d;
+
+ return $this->data['date'];
+ }
+
+ /**
+ * Register DC namespaces
+ *
+ * @return void
+ */
+ protected function registerNamespaces()
+ {
+ $this->getXpath()->registerNamespace('dc10', 'http://purl.org/dc/elements/1.0/');
+ $this->getXpath()->registerNamespace('dc11', 'http://purl.org/dc/elements/1.1/');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/DublinCore/Feed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/DublinCore/Feed.php
new file mode 100644
index 0000000..61959c4
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/DublinCore/Feed.php
@@ -0,0 +1,281 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\DublinCore;
+
+use DateTime;
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Collection;
+use Zend\Feed\Reader\Extension;
+
+class Feed extends Extension\AbstractFeed
+{
+ /**
+ * Get a single author
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getAuthor($index = 0)
+ {
+ $authors = $this->getAuthors();
+
+ if (isset($authors[$index])) {
+ return $authors[$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return array
+ */
+ public function getAuthors()
+ {
+ if (array_key_exists('authors', $this->data)) {
+ return $this->data['authors'];
+ }
+
+ $authors = array();
+ $list = $this->getXpath()->query('//dc11:creator');
+
+ if (!$list->length) {
+ $list = $this->getXpath()->query('//dc10:creator');
+ }
+ if (!$list->length) {
+ $list = $this->getXpath()->query('//dc11:publisher');
+
+ if (!$list->length) {
+ $list = $this->getXpath()->query('//dc10:publisher');
+ }
+ }
+
+ if ($list->length) {
+ foreach ($list as $author) {
+ $authors[] = array(
+ 'name' => $author->nodeValue
+ );
+ }
+ $authors = new Collection\Author(
+ Reader\Reader::arrayUnique($authors)
+ );
+ } else {
+ $authors = null;
+ }
+
+ $this->data['authors'] = $authors;
+
+ return $this->data['authors'];
+ }
+
+ /**
+ * Get the copyright entry
+ *
+ * @return string|null
+ */
+ public function getCopyright()
+ {
+ if (array_key_exists('copyright', $this->data)) {
+ return $this->data['copyright'];
+ }
+
+ $copyright = null;
+ $copyright = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:rights)');
+
+ if (!$copyright) {
+ $copyright = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc10:rights)');
+ }
+
+ if (!$copyright) {
+ $copyright = null;
+ }
+
+ $this->data['copyright'] = $copyright;
+
+ return $this->data['copyright'];
+ }
+
+ /**
+ * Get the feed description
+ *
+ * @return string|null
+ */
+ public function getDescription()
+ {
+ if (array_key_exists('description', $this->data)) {
+ return $this->data['description'];
+ }
+
+ $description = null;
+ $description = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:description)');
+
+ if (!$description) {
+ $description = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc10:description)');
+ }
+
+ if (!$description) {
+ $description = null;
+ }
+
+ $this->data['description'] = $description;
+
+ return $this->data['description'];
+ }
+
+ /**
+ * Get the feed ID
+ *
+ * @return string|null
+ */
+ public function getId()
+ {
+ if (array_key_exists('id', $this->data)) {
+ return $this->data['id'];
+ }
+
+ $id = null;
+ $id = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:identifier)');
+
+ if (!$id) {
+ $id = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc10:identifier)');
+ }
+
+ $this->data['id'] = $id;
+
+ return $this->data['id'];
+ }
+
+ /**
+ * Get the feed language
+ *
+ * @return string|null
+ */
+ public function getLanguage()
+ {
+ if (array_key_exists('language', $this->data)) {
+ return $this->data['language'];
+ }
+
+ $language = null;
+ $language = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:language)');
+
+ if (!$language) {
+ $language = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc10:language)');
+ }
+
+ if (!$language) {
+ $language = null;
+ }
+
+ $this->data['language'] = $language;
+
+ return $this->data['language'];
+ }
+
+ /**
+ * Get the feed title
+ *
+ * @return string|null
+ */
+ public function getTitle()
+ {
+ if (array_key_exists('title', $this->data)) {
+ return $this->data['title'];
+ }
+
+ $title = null;
+ $title = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:title)');
+
+ if (!$title) {
+ $title = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc10:title)');
+ }
+
+ if (!$title) {
+ $title = null;
+ }
+
+ $this->data['title'] = $title;
+
+ return $this->data['title'];
+ }
+
+ /**
+ *
+ *
+ * @return DateTime|null
+ */
+ public function getDate()
+ {
+ if (array_key_exists('date', $this->data)) {
+ return $this->data['date'];
+ }
+
+ $d = null;
+ $date = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:date)');
+
+ if (!$date) {
+ $date = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc10:date)');
+ }
+
+ if ($date) {
+ $d = new DateTime($date);
+ }
+
+ $this->data['date'] = $d;
+
+ return $this->data['date'];
+ }
+
+ /**
+ * Get categories (subjects under DC)
+ *
+ * @return Collection\Category
+ */
+ public function getCategories()
+ {
+ if (array_key_exists('categories', $this->data)) {
+ return $this->data['categories'];
+ }
+
+ $list = $this->getXpath()->evaluate($this->getXpathPrefix() . '//dc11:subject');
+
+ if (!$list->length) {
+ $list = $this->getXpath()->evaluate($this->getXpathPrefix() . '//dc10:subject');
+ }
+
+ if ($list->length) {
+ $categoryCollection = new Collection\Category;
+ foreach ($list as $category) {
+ $categoryCollection[] = array(
+ 'term' => $category->nodeValue,
+ 'scheme' => null,
+ 'label' => $category->nodeValue,
+ );
+ }
+ } else {
+ $categoryCollection = new Collection\Category;
+ }
+
+ $this->data['categories'] = $categoryCollection;
+ return $this->data['categories'];
+ }
+
+ /**
+ * Register the default namespaces for the current feed format
+ *
+ * @return void
+ */
+ protected function registerNamespaces()
+ {
+ $this->getXpath()->registerNamespace('dc10', 'http://purl.org/dc/elements/1.0/');
+ $this->getXpath()->registerNamespace('dc11', 'http://purl.org/dc/elements/1.1/');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Podcast/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Podcast/Entry.php
new file mode 100644
index 0000000..584fd37
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Podcast/Entry.php
@@ -0,0 +1,180 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\Podcast;
+
+use Zend\Feed\Reader\Extension;
+
+/**
+*/
+class Entry extends Extension\AbstractEntry
+{
+ /**
+ * Get the entry author
+ *
+ * @return string
+ */
+ public function getCastAuthor()
+ {
+ if (isset($this->data['author'])) {
+ return $this->data['author'];
+ }
+
+ $author = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:author)');
+
+ if (!$author) {
+ $author = null;
+ }
+
+ $this->data['author'] = $author;
+
+ return $this->data['author'];
+ }
+
+ /**
+ * Get the entry block
+ *
+ * @return string
+ */
+ public function getBlock()
+ {
+ if (isset($this->data['block'])) {
+ return $this->data['block'];
+ }
+
+ $block = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:block)');
+
+ if (!$block) {
+ $block = null;
+ }
+
+ $this->data['block'] = $block;
+
+ return $this->data['block'];
+ }
+
+ /**
+ * Get the entry duration
+ *
+ * @return string
+ */
+ public function getDuration()
+ {
+ if (isset($this->data['duration'])) {
+ return $this->data['duration'];
+ }
+
+ $duration = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:duration)');
+
+ if (!$duration) {
+ $duration = null;
+ }
+
+ $this->data['duration'] = $duration;
+
+ return $this->data['duration'];
+ }
+
+ /**
+ * Get the entry explicit
+ *
+ * @return string
+ */
+ public function getExplicit()
+ {
+ if (isset($this->data['explicit'])) {
+ return $this->data['explicit'];
+ }
+
+ $explicit = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:explicit)');
+
+ if (!$explicit) {
+ $explicit = null;
+ }
+
+ $this->data['explicit'] = $explicit;
+
+ return $this->data['explicit'];
+ }
+
+ /**
+ * Get the entry keywords
+ *
+ * @return string
+ */
+ public function getKeywords()
+ {
+ if (isset($this->data['keywords'])) {
+ return $this->data['keywords'];
+ }
+
+ $keywords = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:keywords)');
+
+ if (!$keywords) {
+ $keywords = null;
+ }
+
+ $this->data['keywords'] = $keywords;
+
+ return $this->data['keywords'];
+ }
+
+ /**
+ * Get the entry subtitle
+ *
+ * @return string
+ */
+ public function getSubtitle()
+ {
+ if (isset($this->data['subtitle'])) {
+ return $this->data['subtitle'];
+ }
+
+ $subtitle = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:subtitle)');
+
+ if (!$subtitle) {
+ $subtitle = null;
+ }
+
+ $this->data['subtitle'] = $subtitle;
+
+ return $this->data['subtitle'];
+ }
+
+ /**
+ * Get the entry summary
+ *
+ * @return string
+ */
+ public function getSummary()
+ {
+ if (isset($this->data['summary'])) {
+ return $this->data['summary'];
+ }
+
+ $summary = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:summary)');
+
+ if (!$summary) {
+ $summary = null;
+ }
+
+ $this->data['summary'] = $summary;
+
+ return $this->data['summary'];
+ }
+
+ /**
+ * Register iTunes namespace
+ *
+ */
+ protected function registerNamespaces()
+ {
+ $this->xpath->registerNamespace('itunes', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Podcast/Feed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Podcast/Feed.php
new file mode 100644
index 0000000..b80bec9
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Podcast/Feed.php
@@ -0,0 +1,277 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\Podcast;
+
+use DOMText;
+use Zend\Feed\Reader\Extension;
+
+/**
+*/
+class Feed extends Extension\AbstractFeed
+{
+ /**
+ * Get the entry author
+ *
+ * @return string
+ */
+ public function getCastAuthor()
+ {
+ if (isset($this->data['author'])) {
+ return $this->data['author'];
+ }
+
+ $author = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:author)');
+
+ if (!$author) {
+ $author = null;
+ }
+
+ $this->data['author'] = $author;
+
+ return $this->data['author'];
+ }
+
+ /**
+ * Get the entry block
+ *
+ * @return string
+ */
+ public function getBlock()
+ {
+ if (isset($this->data['block'])) {
+ return $this->data['block'];
+ }
+
+ $block = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:block)');
+
+ if (!$block) {
+ $block = null;
+ }
+
+ $this->data['block'] = $block;
+
+ return $this->data['block'];
+ }
+
+ /**
+ * Get the entry category
+ *
+ * @return string
+ */
+ public function getItunesCategories()
+ {
+ if (isset($this->data['categories'])) {
+ return $this->data['categories'];
+ }
+
+ $categoryList = $this->xpath->query($this->getXpathPrefix() . '/itunes:category');
+
+ $categories = array();
+
+ if ($categoryList->length > 0) {
+ foreach ($categoryList as $node) {
+ $children = null;
+
+ if ($node->childNodes->length > 0) {
+ $children = array();
+
+ foreach ($node->childNodes as $childNode) {
+ if (!($childNode instanceof DOMText)) {
+ $children[$childNode->getAttribute('text')] = null;
+ }
+ }
+ }
+
+ $categories[$node->getAttribute('text')] = $children;
+ }
+ }
+
+
+ if (!$categories) {
+ $categories = null;
+ }
+
+ $this->data['categories'] = $categories;
+
+ return $this->data['categories'];
+ }
+
+ /**
+ * Get the entry explicit
+ *
+ * @return string
+ */
+ public function getExplicit()
+ {
+ if (isset($this->data['explicit'])) {
+ return $this->data['explicit'];
+ }
+
+ $explicit = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:explicit)');
+
+ if (!$explicit) {
+ $explicit = null;
+ }
+
+ $this->data['explicit'] = $explicit;
+
+ return $this->data['explicit'];
+ }
+
+ /**
+ * Get the entry image
+ *
+ * @return string
+ */
+ public function getItunesImage()
+ {
+ if (isset($this->data['image'])) {
+ return $this->data['image'];
+ }
+
+ $image = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:image/@href)');
+
+ if (!$image) {
+ $image = null;
+ }
+
+ $this->data['image'] = $image;
+
+ return $this->data['image'];
+ }
+
+ /**
+ * Get the entry keywords
+ *
+ * @return string
+ */
+ public function getKeywords()
+ {
+ if (isset($this->data['keywords'])) {
+ return $this->data['keywords'];
+ }
+
+ $keywords = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:keywords)');
+
+ if (!$keywords) {
+ $keywords = null;
+ }
+
+ $this->data['keywords'] = $keywords;
+
+ return $this->data['keywords'];
+ }
+
+ /**
+ * Get the entry's new feed url
+ *
+ * @return string
+ */
+ public function getNewFeedUrl()
+ {
+ if (isset($this->data['new-feed-url'])) {
+ return $this->data['new-feed-url'];
+ }
+
+ $newFeedUrl = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:new-feed-url)');
+
+ if (!$newFeedUrl) {
+ $newFeedUrl = null;
+ }
+
+ $this->data['new-feed-url'] = $newFeedUrl;
+
+ return $this->data['new-feed-url'];
+ }
+
+ /**
+ * Get the entry owner
+ *
+ * @return string
+ */
+ public function getOwner()
+ {
+ if (isset($this->data['owner'])) {
+ return $this->data['owner'];
+ }
+
+ $owner = null;
+
+ $email = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:owner/itunes:email)');
+ $name = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:owner/itunes:name)');
+
+ if (!empty($email)) {
+ $owner = $email . (empty($name) ? '' : ' (' . $name . ')');
+ } elseif (!empty($name)) {
+ $owner = $name;
+ }
+
+ if (!$owner) {
+ $owner = null;
+ }
+
+ $this->data['owner'] = $owner;
+
+ return $this->data['owner'];
+ }
+
+ /**
+ * Get the entry subtitle
+ *
+ * @return string
+ */
+ public function getSubtitle()
+ {
+ if (isset($this->data['subtitle'])) {
+ return $this->data['subtitle'];
+ }
+
+ $subtitle = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:subtitle)');
+
+ if (!$subtitle) {
+ $subtitle = null;
+ }
+
+ $this->data['subtitle'] = $subtitle;
+
+ return $this->data['subtitle'];
+ }
+
+ /**
+ * Get the entry summary
+ *
+ * @return string
+ */
+ public function getSummary()
+ {
+ if (isset($this->data['summary'])) {
+ return $this->data['summary'];
+ }
+
+ $summary = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/itunes:summary)');
+
+ if (!$summary) {
+ $summary = null;
+ }
+
+ $this->data['summary'] = $summary;
+
+ return $this->data['summary'];
+ }
+
+ /**
+ * Register iTunes namespace
+ *
+ */
+ protected function registerNamespaces()
+ {
+ $this->xpath->registerNamespace('itunes', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Slash/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Slash/Entry.php
new file mode 100644
index 0000000..abd7eda
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Slash/Entry.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\Slash;
+
+use Zend\Feed\Reader\Extension;
+
+/**
+*/
+class Entry extends Extension\AbstractEntry
+{
+ /**
+ * Get the entry section
+ *
+ * @return string|null
+ */
+ public function getSection()
+ {
+ return $this->getData('section');
+ }
+
+ /**
+ * Get the entry department
+ *
+ * @return string|null
+ */
+ public function getDepartment()
+ {
+ return $this->getData('department');
+ }
+
+ /**
+ * Get the entry hit_parade
+ *
+ * @return array
+ */
+ public function getHitParade()
+ {
+ $name = 'hit_parade';
+
+ if (isset($this->data[$name])) {
+ return $this->data[$name];
+ }
+
+ $stringParade = $this->getData($name);
+ $hitParade = array();
+
+ if (!empty($stringParade)) {
+ $stringParade = explode(',', $stringParade);
+
+ foreach ($stringParade as $hit)
+ $hitParade[] = $hit + 0; //cast to integer
+ }
+
+ $this->data[$name] = $hitParade;
+ return $hitParade;
+ }
+
+ /**
+ * Get the entry comments
+ *
+ * @return int
+ */
+ public function getCommentCount()
+ {
+ $name = 'comments';
+
+ if (isset($this->data[$name])) {
+ return $this->data[$name];
+ }
+
+ $comments = $this->getData($name, 'string');
+
+ if (!$comments) {
+ $this->data[$name] = null;
+ return $this->data[$name];
+ }
+
+ return $comments;
+ }
+
+ /**
+ * Get the entry data specified by name
+ * @param string $name
+ * @param string $type
+ *
+ * @return mixed|null
+ */
+ protected function getData($name, $type = 'string')
+ {
+ if (array_key_exists($name, $this->data)) {
+ return $this->data[$name];
+ }
+
+ $data = $this->xpath->evaluate($type . '(' . $this->getXpathPrefix() . '/slash10:' . $name . ')');
+
+ if (!$data) {
+ $data = null;
+ }
+
+ $this->data[$name] = $data;
+
+ return $data;
+ }
+
+ /**
+ * Register Slash namespaces
+ *
+ * @return void
+ */
+ protected function registerNamespaces()
+ {
+ $this->xpath->registerNamespace('slash10', 'http://purl.org/rss/1.0/modules/slash/');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Syndication/Feed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Syndication/Feed.php
new file mode 100644
index 0000000..75f031b
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Syndication/Feed.php
@@ -0,0 +1,149 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\Syndication;
+
+use DateTime;
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Extension;
+
+class Feed extends \Zend\Feed\Reader\Extension\AbstractFeed
+{
+ /**
+ * Get update period
+ *
+ * @return string
+ * @throws Reader\Exception\InvalidArgumentException
+ */
+ public function getUpdatePeriod()
+ {
+ $name = 'updatePeriod';
+ $period = $this->_getData($name);
+
+ if ($period === null) {
+ $this->data[$name] = 'daily';
+ return 'daily'; //Default specified by spec
+ }
+
+ switch ($period) {
+ case 'hourly':
+ case 'daily':
+ case 'weekly':
+ case 'yearly':
+ return $period;
+ default:
+ throw new Reader\Exception\InvalidArgumentException("Feed specified invalid update period: '$period'."
+ . " Must be one of hourly, daily, weekly or yearly"
+ );
+ }
+ }
+
+ /**
+ * Get update frequency
+ * @return int
+ */
+ public function getUpdateFrequency()
+ {
+ $name = 'updateFrequency';
+ $freq = $this->_getData($name, 'number');
+
+ if (!$freq || $freq < 1) {
+ $this->data[$name] = 1;
+ return 1;
+ }
+
+ return $freq;
+ }
+
+ /**
+ * Get update frequency as ticks
+ * @return int
+ */
+ public function getUpdateFrequencyAsTicks()
+ {
+ $name = 'updateFrequency';
+ $freq = $this->_getData($name, 'number');
+
+ if (!$freq || $freq < 1) {
+ $this->data[$name] = 1;
+ $freq = 1;
+ }
+
+ $period = $this->getUpdatePeriod();
+ $ticks = 1;
+
+ switch ($period) {
+ case 'yearly':
+ $ticks *= 52; //TODO: fix generalisation, how?
+ // no break
+ case 'weekly':
+ $ticks *= 7;
+ // no break
+ case 'daily':
+ $ticks *= 24;
+ // no break
+ case 'hourly':
+ $ticks *= 3600;
+ break;
+ default: //Never arrive here, exception thrown in getPeriod()
+ break;
+ }
+
+ return $ticks / $freq;
+ }
+
+ /**
+ * Get update base
+ *
+ * @return DateTime|null
+ */
+ public function getUpdateBase()
+ {
+ $updateBase = $this->_getData('updateBase');
+ $date = null;
+ if ($updateBase) {
+ $date = DateTime::createFromFormat(DateTime::W3C, $updateBase);
+ }
+ return $date;
+ }
+
+ /**
+ * Get the entry data specified by name
+ *
+ * @param string $name
+ * @param string $type
+ * @return mixed|null
+ */
+ private function _getData($name, $type = 'string')
+ {
+ if (array_key_exists($name, $this->data)) {
+ return $this->data[$name];
+ }
+
+ $data = $this->xpath->evaluate($type . '(' . $this->getXpathPrefix() . '/syn10:' . $name . ')');
+
+ if (!$data) {
+ $data = null;
+ }
+
+ $this->data[$name] = $data;
+
+ return $data;
+ }
+
+ /**
+ * Register Syndication namespaces
+ *
+ * @return void
+ */
+ protected function registerNamespaces()
+ {
+ $this->xpath->registerNamespace('syn10', 'http://purl.org/rss/1.0/modules/syndication/');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Thread/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Thread/Entry.php
new file mode 100644
index 0000000..ceaee85
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/Thread/Entry.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\Thread;
+
+use Zend\Feed\Reader\Extension;
+
+/**
+*/
+class Entry extends Extension\AbstractEntry
+{
+ /**
+ * Get the "in-reply-to" value
+ *
+ * @return string
+ */
+ public function getInReplyTo()
+ {
+ // TODO: to be implemented
+ }
+
+ // TODO: Implement "replies" and "updated" constructs from standard
+
+ /**
+ * Get the total number of threaded responses (i.e comments)
+ *
+ * @return int|null
+ */
+ public function getCommentCount()
+ {
+ return $this->getData('total');
+ }
+
+ /**
+ * Get the entry data specified by name
+ *
+ * @param string $name
+ * @return mixed|null
+ */
+ protected function getData($name)
+ {
+ if (array_key_exists($name, $this->data)) {
+ return $this->data[$name];
+ }
+
+ $data = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/thread10:' . $name . ')');
+
+ if (!$data) {
+ $data = null;
+ }
+
+ $this->data[$name] = $data;
+
+ return $data;
+ }
+
+ /**
+ * Register Atom Thread Extension 1.0 namespace
+ *
+ * @return void
+ */
+ protected function registerNamespaces()
+ {
+ $this->xpath->registerNamespace('thread10', 'http://purl.org/syndication/thread/1.0');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/WellFormedWeb/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/WellFormedWeb/Entry.php
new file mode 100644
index 0000000..cc52bc9
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Extension/WellFormedWeb/Entry.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Extension\WellFormedWeb;
+
+use Zend\Feed\Reader\Extension;
+
+/**
+*/
+class Entry extends Extension\AbstractEntry
+{
+ /**
+ * Get the entry comment Uri
+ *
+ * @return string|null
+ */
+ public function getCommentFeedLink()
+ {
+ $name = 'commentRss';
+ if (array_key_exists($name, $this->data)) {
+ return $this->data[$name];
+ }
+
+ $data = $this->xpath->evaluate('string(' . $this->getXpathPrefix() . '/wfw:' . $name . ')');
+
+ if (!$data) {
+ $data = null;
+ }
+
+ $this->data[$name] = $data;
+
+ return $data;
+ }
+
+ /**
+ * Register Slash namespaces
+ *
+ * @return void
+ */
+ protected function registerNamespaces()
+ {
+ $this->xpath->registerNamespace('wfw', 'http://wellformedweb.org/CommentAPI/');
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionManager.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionManager.php
new file mode 100644
index 0000000..b6fa68d
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionManager.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader;
+
+/**
+ * Default implementation of ExtensionManagerInterface
+ *
+ * Decorator of ExtensionPluginManager.
+ */
+class ExtensionManager implements ExtensionManagerInterface
+{
+ protected $pluginManager;
+
+ /**
+ * Constructor
+ *
+ * Seeds the extension manager with a plugin manager; if none provided,
+ * creates an instance.
+ *
+ * @param null|ExtensionPluginManager $pluginManager
+ */
+ public function __construct(ExtensionPluginManager $pluginManager = null)
+ {
+ if (null === $pluginManager) {
+ $pluginManager = new ExtensionPluginManager();
+ }
+ $this->pluginManager = $pluginManager;
+ }
+
+ /**
+ * Method overloading
+ *
+ * Proxy to composed ExtensionPluginManager instance.
+ *
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ * @throws Exception\BadMethodCallException
+ */
+ public function __call($method, $args)
+ {
+ if (!method_exists($this->pluginManager, $method)) {
+ throw new Exception\BadMethodCallException(sprintf(
+ 'Method by name of %s does not exist in %s',
+ $method,
+ __CLASS__
+ ));
+ }
+ return call_user_func_array(array($this->pluginManager, $method), $args);
+ }
+
+ /**
+ * Get the named extension
+ *
+ * @param string $name
+ * @return Extension\AbstractEntry|Extension\AbstractFeed
+ */
+ public function get($name)
+ {
+ return $this->pluginManager->get($name);
+ }
+
+ /**
+ * Do we have the named extension?
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function has($name)
+ {
+ return $this->pluginManager->has($name);
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionManagerInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionManagerInterface.php
new file mode 100644
index 0000000..6ae9b67
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionManagerInterface.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader;
+
+interface ExtensionManagerInterface
+{
+ /**
+ * Do we have the extension?
+ *
+ * @param string $extension
+ * @return bool
+ */
+ public function has($extension);
+
+ /**
+ * Retrieve the extension
+ *
+ * @param string $extension
+ * @return mixed
+ */
+ public function get($extension);
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionPluginManager.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionPluginManager.php
new file mode 100644
index 0000000..8222ee2
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/ExtensionPluginManager.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader;
+
+use Zend\ServiceManager\AbstractPluginManager;
+
+/**
+ * Plugin manager implementation for feed reader extensions based on the
+ * AbstractPluginManager.
+ *
+ * Validation checks that we have an Extension\AbstractEntry or
+ * Extension\AbstractFeed.
+ */
+class ExtensionPluginManager extends AbstractPluginManager
+{
+ /**
+ * Default set of extension classes
+ *
+ * @var array
+ */
+ protected $invokableClasses = array(
+ 'atomentry' => 'Zend\Feed\Reader\Extension\Atom\Entry',
+ 'atomfeed' => 'Zend\Feed\Reader\Extension\Atom\Feed',
+ 'contententry' => 'Zend\Feed\Reader\Extension\Content\Entry',
+ 'creativecommonsentry' => 'Zend\Feed\Reader\Extension\CreativeCommons\Entry',
+ 'creativecommonsfeed' => 'Zend\Feed\Reader\Extension\CreativeCommons\Feed',
+ 'dublincoreentry' => 'Zend\Feed\Reader\Extension\DublinCore\Entry',
+ 'dublincorefeed' => 'Zend\Feed\Reader\Extension\DublinCore\Feed',
+ 'podcastentry' => 'Zend\Feed\Reader\Extension\Podcast\Entry',
+ 'podcastfeed' => 'Zend\Feed\Reader\Extension\Podcast\Feed',
+ 'slashentry' => 'Zend\Feed\Reader\Extension\Slash\Entry',
+ 'syndicationfeed' => 'Zend\Feed\Reader\Extension\Syndication\Feed',
+ 'threadentry' => 'Zend\Feed\Reader\Extension\Thread\Entry',
+ 'wellformedwebentry' => 'Zend\Feed\Reader\Extension\WellFormedWeb\Entry',
+ );
+
+ /**
+ * Do not share instances
+ *
+ * @var bool
+ */
+ protected $shareByDefault = false;
+
+ /**
+ * Validate the plugin
+ *
+ * Checks that the extension loaded is of a valid type.
+ *
+ * @param mixed $plugin
+ * @return void
+ * @throws Exception\InvalidArgumentException if invalid
+ */
+ public function validatePlugin($plugin)
+ {
+ if ($plugin instanceof Extension\AbstractEntry
+ || $plugin instanceof Extension\AbstractFeed
+ ) {
+ // we're okay
+ return;
+ }
+
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'Plugin of type %s is invalid; must implement %s\Extension\AbstractFeed '
+ . 'or %s\Extension\AbstractEntry',
+ (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
+ __NAMESPACE__,
+ __NAMESPACE__
+ ));
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/AbstractFeed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/AbstractFeed.php
new file mode 100644
index 0000000..6438184
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/AbstractFeed.php
@@ -0,0 +1,307 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Feed;
+
+use DOMDocument;
+use DOMElement;
+use DOMXPath;
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Exception;
+
+/**
+*/
+abstract class AbstractFeed implements FeedInterface
+{
+ /**
+ * Parsed feed data
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * Parsed feed data in the shape of a DOMDocument
+ *
+ * @var DOMDocument
+ */
+ protected $domDocument = null;
+
+ /**
+ * An array of parsed feed entries
+ *
+ * @var array
+ */
+ protected $entries = array();
+
+ /**
+ * A pointer for the iterator to keep track of the entries array
+ *
+ * @var int
+ */
+ protected $entriesKey = 0;
+
+ /**
+ * The base XPath query used to retrieve feed data
+ *
+ * @var DOMXPath
+ */
+ protected $xpath = null;
+
+ /**
+ * Array of loaded extensions
+ *
+ * @var array
+ */
+ protected $extensions = array();
+
+ /**
+ * Original Source URI (set if imported from a URI)
+ *
+ * @var string
+ */
+ protected $originalSourceUri = null;
+
+ /**
+ * Constructor
+ *
+ * @param DOMDocument $domDocument The DOM object for the feed's XML
+ * @param string $type Feed type
+ */
+ public function __construct(DOMDocument $domDocument, $type = null)
+ {
+ $this->domDocument = $domDocument;
+ $this->xpath = new DOMXPath($this->domDocument);
+
+ if ($type !== null) {
+ $this->data['type'] = $type;
+ } else {
+ $this->data['type'] = Reader\Reader::detectType($this->domDocument);
+ }
+ $this->registerNamespaces();
+ $this->indexEntries();
+ $this->loadExtensions();
+ }
+
+ /**
+ * Set an original source URI for the feed being parsed. This value
+ * is returned from getFeedLink() method if the feed does not carry
+ * a self-referencing URI.
+ *
+ * @param string $uri
+ */
+ public function setOriginalSourceUri($uri)
+ {
+ $this->originalSourceUri = $uri;
+ }
+
+ /**
+ * Get an original source URI for the feed being parsed. Returns null if
+ * unset or the feed was not imported from a URI.
+ *
+ * @return string|null
+ */
+ public function getOriginalSourceUri()
+ {
+ return $this->originalSourceUri;
+ }
+
+ /**
+ * Get the number of feed entries.
+ * Required by the Iterator interface.
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->entries);
+ }
+
+ /**
+ * Return the current entry
+ *
+ * @return \Zend\Feed\Reader\Entry\EntryInterface
+ */
+ public function current()
+ {
+ if (substr($this->getType(), 0, 3) == 'rss') {
+ $reader = new Reader\Entry\Rss($this->entries[$this->key()], $this->key(), $this->getType());
+ } else {
+ $reader = new Reader\Entry\Atom($this->entries[$this->key()], $this->key(), $this->getType());
+ }
+
+ $reader->setXpath($this->xpath);
+
+ return $reader;
+ }
+
+ /**
+ * Get the DOM
+ *
+ * @return DOMDocument
+ */
+ public function getDomDocument()
+ {
+ return $this->domDocument;
+ }
+
+ /**
+ * Get the Feed's encoding
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ $assumed = $this->getDomDocument()->encoding;
+ if (empty($assumed)) {
+ $assumed = 'UTF-8';
+ }
+ return $assumed;
+ }
+
+ /**
+ * Get feed as xml
+ *
+ * @return string
+ */
+ public function saveXml()
+ {
+ return $this->getDomDocument()->saveXml();
+ }
+
+ /**
+ * Get the DOMElement representing the items/feed element
+ *
+ * @return DOMElement
+ */
+ public function getElement()
+ {
+ return $this->getDomDocument()->documentElement;
+ }
+
+ /**
+ * Get the DOMXPath object for this feed
+ *
+ * @return DOMXPath
+ */
+ public function getXpath()
+ {
+ return $this->xpath;
+ }
+
+ /**
+ * Get the feed type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->data['type'];
+ }
+
+ /**
+ * Return the current feed key
+ *
+ * @return int
+ */
+ public function key()
+ {
+ return $this->entriesKey;
+ }
+
+ /**
+ * Move the feed pointer forward
+ *
+ */
+ public function next()
+ {
+ ++$this->entriesKey;
+ }
+
+ /**
+ * Reset the pointer in the feed object
+ *
+ */
+ public function rewind()
+ {
+ $this->entriesKey = 0;
+ }
+
+ /**
+ * Check to see if the iterator is still valid
+ *
+ * @return bool
+ */
+ public function valid()
+ {
+ return 0 <= $this->entriesKey && $this->entriesKey < $this->count();
+ }
+
+ public function getExtensions()
+ {
+ return $this->extensions;
+ }
+
+ public function __call($method, $args)
+ {
+ foreach ($this->extensions as $extension) {
+ if (method_exists($extension, $method)) {
+ return call_user_func_array(array($extension, $method), $args);
+ }
+ }
+ throw new Exception\BadMethodCallException('Method: ' . $method
+ . 'does not exist and could not be located on a registered Extension');
+ }
+
+ /**
+ * Return an Extension object with the matching name (postfixed with _Feed)
+ *
+ * @param string $name
+ * @return \Zend\Feed\Reader\Extension\AbstractFeed
+ */
+ public function getExtension($name)
+ {
+ if (array_key_exists($name . '\\Feed', $this->extensions)) {
+ return $this->extensions[$name . '\\Feed'];
+ }
+ return null;
+ }
+
+ protected function loadExtensions()
+ {
+ $all = Reader\Reader::getExtensions();
+ $manager = Reader\Reader::getExtensionManager();
+ $feed = $all['feed'];
+ foreach ($feed as $extension) {
+ if (in_array($extension, $all['core'])) {
+ continue;
+ }
+ if (!$manager->has($extension)) {
+ throw new Exception\RuntimeException(sprintf('Unable to load extension "%s"; cannot find class', $extension));
+ }
+ $plugin = $manager->get($extension);
+ $plugin->setDomDocument($this->getDomDocument());
+ $plugin->setType($this->data['type']);
+ $plugin->setXpath($this->xpath);
+ $this->extensions[$extension] = $plugin;
+ }
+ }
+
+ /**
+ * Read all entries to the internal entries array
+ *
+ */
+ abstract protected function indexEntries();
+
+ /**
+ * Register the default namespaces for the current feed format
+ *
+ */
+ abstract protected function registerNamespaces();
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Atom.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Atom.php
new file mode 100644
index 0000000..cc39438
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Atom.php
@@ -0,0 +1,410 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Feed;
+
+use DOMDocument;
+use Zend\Feed\Reader;
+
+/**
+*/
+class Atom extends AbstractFeed
+{
+
+ /**
+ * Constructor
+ *
+ * @param DOMDocument $dom
+ * @param string $type
+ */
+ public function __construct(DOMDocument $dom, $type = null)
+ {
+ parent::__construct($dom, $type);
+ $manager = Reader\Reader::getExtensionManager();
+
+ $atomFeed = $manager->get('Atom\Feed');
+ $atomFeed->setDomDocument($dom);
+ $atomFeed->setType($this->data['type']);
+ $atomFeed->setXpath($this->xpath);
+ $this->extensions['Atom\\Feed'] = $atomFeed;
+
+ $atomFeed = $manager->get('DublinCore\Feed');
+ $atomFeed->setDomDocument($dom);
+ $atomFeed->setType($this->data['type']);
+ $atomFeed->setXpath($this->xpath);
+ $this->extensions['DublinCore\\Feed'] = $atomFeed;
+
+ foreach ($this->extensions as $extension) {
+ $extension->setXpathPrefix('/atom:feed');
+ }
+ }
+
+ /**
+ * Get a single author
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getAuthor($index = 0)
+ {
+ $authors = $this->getAuthors();
+
+ if (isset($authors[$index])) {
+ return $authors[$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return array
+ */
+ public function getAuthors()
+ {
+ if (array_key_exists('authors', $this->data)) {
+ return $this->data['authors'];
+ }
+
+ $authors = $this->getExtension('Atom')->getAuthors();
+
+ $this->data['authors'] = $authors;
+
+ return $this->data['authors'];
+ }
+
+ /**
+ * Get the copyright entry
+ *
+ * @return string|null
+ */
+ public function getCopyright()
+ {
+ if (array_key_exists('copyright', $this->data)) {
+ return $this->data['copyright'];
+ }
+
+ $copyright = $this->getExtension('Atom')->getCopyright();
+
+ if (!$copyright) {
+ $copyright = null;
+ }
+
+ $this->data['copyright'] = $copyright;
+
+ return $this->data['copyright'];
+ }
+
+ /**
+ * Get the feed creation date
+ *
+ * @return string|null
+ */
+ public function getDateCreated()
+ {
+ if (array_key_exists('datecreated', $this->data)) {
+ return $this->data['datecreated'];
+ }
+
+ $dateCreated = $this->getExtension('Atom')->getDateCreated();
+
+ if (!$dateCreated) {
+ $dateCreated = null;
+ }
+
+ $this->data['datecreated'] = $dateCreated;
+
+ return $this->data['datecreated'];
+ }
+
+ /**
+ * Get the feed modification date
+ *
+ * @return string|null
+ */
+ public function getDateModified()
+ {
+ if (array_key_exists('datemodified', $this->data)) {
+ return $this->data['datemodified'];
+ }
+
+ $dateModified = $this->getExtension('Atom')->getDateModified();
+
+ if (!$dateModified) {
+ $dateModified = null;
+ }
+
+ $this->data['datemodified'] = $dateModified;
+
+ return $this->data['datemodified'];
+ }
+
+ /**
+ * Get the feed lastBuild date. This is not implemented in Atom.
+ *
+ * @return string|null
+ */
+ public function getLastBuildDate()
+ {
+ return null;
+ }
+
+ /**
+ * Get the feed description
+ *
+ * @return string|null
+ */
+ public function getDescription()
+ {
+ if (array_key_exists('description', $this->data)) {
+ return $this->data['description'];
+ }
+
+ $description = $this->getExtension('Atom')->getDescription();
+
+ if (!$description) {
+ $description = null;
+ }
+
+ $this->data['description'] = $description;
+
+ return $this->data['description'];
+ }
+
+ /**
+ * Get the feed generator entry
+ *
+ * @return string|null
+ */
+ public function getGenerator()
+ {
+ if (array_key_exists('generator', $this->data)) {
+ return $this->data['generator'];
+ }
+
+ $generator = $this->getExtension('Atom')->getGenerator();
+
+ $this->data['generator'] = $generator;
+
+ return $this->data['generator'];
+ }
+
+ /**
+ * Get the feed ID
+ *
+ * @return string|null
+ */
+ public function getId()
+ {
+ if (array_key_exists('id', $this->data)) {
+ return $this->data['id'];
+ }
+
+ $id = $this->getExtension('Atom')->getId();
+
+ $this->data['id'] = $id;
+
+ return $this->data['id'];
+ }
+
+ /**
+ * Get the feed language
+ *
+ * @return string|null
+ */
+ public function getLanguage()
+ {
+ if (array_key_exists('language', $this->data)) {
+ return $this->data['language'];
+ }
+
+ $language = $this->getExtension('Atom')->getLanguage();
+
+ if (!$language) {
+ $language = $this->xpath->evaluate('string(//@xml:lang[1])');
+ }
+
+ if (!$language) {
+ $language = null;
+ }
+
+ $this->data['language'] = $language;
+
+ return $this->data['language'];
+ }
+
+ /**
+ * Get a link to the source website
+ *
+ * @return string|null
+ */
+ public function getBaseUrl()
+ {
+ if (array_key_exists('baseUrl', $this->data)) {
+ return $this->data['baseUrl'];
+ }
+
+ $baseUrl = $this->getExtension('Atom')->getBaseUrl();
+
+ $this->data['baseUrl'] = $baseUrl;
+
+ return $this->data['baseUrl'];
+ }
+
+ /**
+ * Get a link to the source website
+ *
+ * @return string|null
+ */
+ public function getLink()
+ {
+ if (array_key_exists('link', $this->data)) {
+ return $this->data['link'];
+ }
+
+ $link = $this->getExtension('Atom')->getLink();
+
+ $this->data['link'] = $link;
+
+ return $this->data['link'];
+ }
+
+ /**
+ * Get feed image data
+ *
+ * @return array|null
+ */
+ public function getImage()
+ {
+ if (array_key_exists('image', $this->data)) {
+ return $this->data['image'];
+ }
+
+ $link = $this->getExtension('Atom')->getImage();
+
+ $this->data['image'] = $link;
+
+ return $this->data['image'];
+ }
+
+ /**
+ * Get a link to the feed's XML Url
+ *
+ * @return string|null
+ */
+ public function getFeedLink()
+ {
+ if (array_key_exists('feedlink', $this->data)) {
+ return $this->data['feedlink'];
+ }
+
+ $link = $this->getExtension('Atom')->getFeedLink();
+
+ if ($link === null || empty($link)) {
+ $link = $this->getOriginalSourceUri();
+ }
+
+ $this->data['feedlink'] = $link;
+
+ return $this->data['feedlink'];
+ }
+
+ /**
+ * Get the feed title
+ *
+ * @return string|null
+ */
+ public function getTitle()
+ {
+ if (array_key_exists('title', $this->data)) {
+ return $this->data['title'];
+ }
+
+ $title = $this->getExtension('Atom')->getTitle();
+
+ $this->data['title'] = $title;
+
+ return $this->data['title'];
+ }
+
+ /**
+ * Get an array of any supported Pusubhubbub endpoints
+ *
+ * @return array|null
+ */
+ public function getHubs()
+ {
+ if (array_key_exists('hubs', $this->data)) {
+ return $this->data['hubs'];
+ }
+
+ $hubs = $this->getExtension('Atom')->getHubs();
+
+ $this->data['hubs'] = $hubs;
+
+ return $this->data['hubs'];
+ }
+
+ /**
+ * Get all categories
+ *
+ * @return Reader\Collection\Category
+ */
+ public function getCategories()
+ {
+ if (array_key_exists('categories', $this->data)) {
+ return $this->data['categories'];
+ }
+
+ $categoryCollection = $this->getExtension('Atom')->getCategories();
+
+ if (count($categoryCollection) == 0) {
+ $categoryCollection = $this->getExtension('DublinCore')->getCategories();
+ }
+
+ $this->data['categories'] = $categoryCollection;
+
+ return $this->data['categories'];
+ }
+
+ /**
+ * Read all entries to the internal entries array
+ *
+ * @return void
+ */
+ protected function indexEntries()
+ {
+ if ($this->getType() == Reader\Reader::TYPE_ATOM_10 ||
+ $this->getType() == Reader\Reader::TYPE_ATOM_03) {
+ $entries = array();
+ $entries = $this->xpath->evaluate('//atom:entry');
+
+ foreach ($entries as $index => $entry) {
+ $this->entries[$index] = $entry;
+ }
+ }
+ }
+
+ /**
+ * Register the default namespaces for the current feed format
+ *
+ */
+ protected function registerNamespaces()
+ {
+ switch ($this->data['type']) {
+ case Reader\Reader::TYPE_ATOM_03:
+ $this->xpath->registerNamespace('atom', Reader\Reader::NAMESPACE_ATOM_03);
+ break;
+ case Reader\Reader::TYPE_ATOM_10:
+ default:
+ $this->xpath->registerNamespace('atom', Reader\Reader::NAMESPACE_ATOM_10);
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Atom/Source.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Atom/Source.php
new file mode 100644
index 0000000..3055dc3
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Atom/Source.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Feed\Atom;
+
+use DOMElement;
+use DOMXPath;
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Feed;
+
+/**
+*/
+class Source extends Feed\Atom
+{
+
+ /**
+ * Constructor: Create a Source object which is largely just a normal
+ * Zend\Feed\Reader\AbstractFeed object only designed to retrieve feed level
+ * metadata from an Atom entry's source element.
+ *
+ * @param DOMElement $source
+ * @param string $xpathPrefix Passed from parent Entry object
+ * @param string $type Nearly always Atom 1.0
+ */
+ public function __construct(DOMElement $source, $xpathPrefix, $type = Reader\Reader::TYPE_ATOM_10)
+ {
+ $this->domDocument = $source->ownerDocument;
+ $this->xpath = new DOMXPath($this->domDocument);
+ $this->data['type'] = $type;
+ $this->registerNamespaces();
+ $this->loadExtensions();
+
+ $manager = Reader\Reader::getExtensionManager();
+ $extensions = array('Atom\Feed', 'DublinCore\Feed');
+
+ foreach ($extensions as $name) {
+ $extension = $manager->get($name);
+ $extension->setDomDocument($this->domDocument);
+ $extension->setType($this->data['type']);
+ $extension->setXpath($this->xpath);
+ $this->extensions[$name] = $extension;
+ }
+
+ foreach ($this->extensions as $extension) {
+ $extension->setXpathPrefix(rtrim($xpathPrefix, '/') . '/atom:source');
+ }
+ }
+
+ /**
+ * Since this is not an Entry carrier but a vehicle for Feed metadata, any
+ * applicable Entry methods are stubbed out and do nothing.
+ */
+
+ /**
+ * @return void
+ */
+ public function count() {}
+
+ /**
+ * @return void
+ */
+ public function current() {}
+
+ /**
+ * @return void
+ */
+ public function key() {}
+
+ /**
+ * @return void
+ */
+ public function next() {}
+
+ /**
+ * @return void
+ */
+ public function rewind() {}
+
+ /**
+ * @return void
+ */
+ public function valid() {}
+
+ /**
+ * @return void
+ */
+ protected function indexEntries() {}
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/FeedInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/FeedInterface.php
new file mode 100644
index 0000000..c66bb7b
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/FeedInterface.php
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Feed;
+
+use Countable;
+use Iterator;
+
+/**
+*/
+interface FeedInterface extends Iterator, Countable
+{
+ /**
+ * Get a single author
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getAuthor($index = 0);
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return array
+ */
+ public function getAuthors();
+
+ /**
+ * Get the copyright entry
+ *
+ * @return string|null
+ */
+ public function getCopyright();
+
+ /**
+ * Get the feed creation date
+ *
+ * @return string|null
+ */
+ public function getDateCreated();
+
+ /**
+ * Get the feed modification date
+ *
+ * @return string|null
+ */
+ public function getDateModified();
+
+ /**
+ * Get the feed description
+ *
+ * @return string|null
+ */
+ public function getDescription();
+
+ /**
+ * Get the feed generator entry
+ *
+ * @return string|null
+ */
+ public function getGenerator();
+
+ /**
+ * Get the feed ID
+ *
+ * @return string|null
+ */
+ public function getId();
+
+ /**
+ * Get the feed language
+ *
+ * @return string|null
+ */
+ public function getLanguage();
+
+ /**
+ * Get a link to the HTML source
+ *
+ * @return string|null
+ */
+ public function getLink();
+
+ /**
+ * Get a link to the XML feed
+ *
+ * @return string|null
+ */
+ public function getFeedLink();
+
+ /**
+ * Get the feed title
+ *
+ * @return string|null
+ */
+ public function getTitle();
+
+ /**
+ * Get all categories
+ *
+ * @return \Zend\Feed\Reader\Collection\Category
+ */
+ public function getCategories();
+
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Rss.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Rss.php
new file mode 100644
index 0000000..61ce229
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Feed/Rss.php
@@ -0,0 +1,709 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Feed;
+
+use DateTime;
+use DOMDocument;
+use Zend\Feed\Reader;
+use Zend\Feed\Reader\Collection;
+use Zend\Feed\Reader\Exception;
+
+/**
+*/
+class Rss extends AbstractFeed
+{
+
+ /**
+ * Constructor
+ *
+ * @param DOMDocument $dom
+ * @param string $type
+ */
+ public function __construct(DOMDocument $dom, $type = null)
+ {
+ parent::__construct($dom, $type);
+
+ $manager = Reader\Reader::getExtensionManager();
+
+ $feed = $manager->get('DublinCore\Feed');
+ $feed->setDomDocument($dom);
+ $feed->setType($this->data['type']);
+ $feed->setXpath($this->xpath);
+ $this->extensions['DublinCore\Feed'] = $feed;
+
+ $feed = $manager->get('Atom\Feed');
+ $feed->setDomDocument($dom);
+ $feed->setType($this->data['type']);
+ $feed->setXpath($this->xpath);
+ $this->extensions['Atom\Feed'] = $feed;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10
+ && $this->getType() !== Reader\Reader::TYPE_RSS_090
+ ) {
+ $xpathPrefix = '/rss/channel';
+ } else {
+ $xpathPrefix = '/rdf:RDF/rss:channel';
+ }
+ foreach ($this->extensions as $extension) {
+ $extension->setXpathPrefix($xpathPrefix);
+ }
+ }
+
+ /**
+ * Get a single author
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getAuthor($index = 0)
+ {
+ $authors = $this->getAuthors();
+
+ if (isset($authors[$index])) {
+ return $authors[$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return array
+ */
+ public function getAuthors()
+ {
+ if (array_key_exists('authors', $this->data)) {
+ return $this->data['authors'];
+ }
+
+ $authors = array();
+ $authorsDc = $this->getExtension('DublinCore')->getAuthors();
+ if (!empty($authorsDc)) {
+ foreach ($authorsDc as $author) {
+ $authors[] = array(
+ 'name' => $author['name']
+ );
+ }
+ }
+
+ /**
+ * Technically RSS doesn't specific author element use at the feed level
+ * but it's supported on a "just in case" basis.
+ */
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10
+ && $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $list = $this->xpath->query('//author');
+ } else {
+ $list = $this->xpath->query('//rss:author');
+ }
+ if ($list->length) {
+ foreach ($list as $author) {
+ $string = trim($author->nodeValue);
+ $email = null;
+ $name = null;
+ $data = array();
+ // Pretty rough parsing - but it's a catchall
+ if (preg_match("/^.*@[^ ]*/", $string, $matches)) {
+ $data['email'] = trim($matches[0]);
+ if (preg_match("/\((.*)\)$/", $string, $matches)) {
+ $data['name'] = $matches[1];
+ }
+ $authors[] = $data;
+ }
+ }
+ }
+
+ if (count($authors) == 0) {
+ $authors = $this->getExtension('Atom')->getAuthors();
+ } else {
+ $authors = new Reader\Collection\Author(
+ Reader\Reader::arrayUnique($authors)
+ );
+ }
+
+ if (count($authors) == 0) {
+ $authors = null;
+ }
+
+ $this->data['authors'] = $authors;
+
+ return $this->data['authors'];
+ }
+
+ /**
+ * Get the copyright entry
+ *
+ * @return string|null
+ */
+ public function getCopyright()
+ {
+ if (array_key_exists('copyright', $this->data)) {
+ return $this->data['copyright'];
+ }
+
+ $copyright = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $copyright = $this->xpath->evaluate('string(/rss/channel/copyright)');
+ }
+
+ if (!$copyright && $this->getExtension('DublinCore') !== null) {
+ $copyright = $this->getExtension('DublinCore')->getCopyright();
+ }
+
+ if (empty($copyright)) {
+ $copyright = $this->getExtension('Atom')->getCopyright();
+ }
+
+ if (!$copyright) {
+ $copyright = null;
+ }
+
+ $this->data['copyright'] = $copyright;
+
+ return $this->data['copyright'];
+ }
+
+ /**
+ * Get the feed creation date
+ *
+ * @return string|null
+ */
+ public function getDateCreated()
+ {
+ return $this->getDateModified();
+ }
+
+ /**
+ * Get the feed modification date
+ *
+ * @return DateTime
+ * @throws Exception\RuntimeException
+ */
+ public function getDateModified()
+ {
+ if (array_key_exists('datemodified', $this->data)) {
+ return $this->data['datemodified'];
+ }
+
+ $dateModified = null;
+ $date = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $dateModified = $this->xpath->evaluate('string(/rss/channel/pubDate)');
+ if (!$dateModified) {
+ $dateModified = $this->xpath->evaluate('string(/rss/channel/lastBuildDate)');
+ }
+ if ($dateModified) {
+ $dateModifiedParsed = strtotime($dateModified);
+ if ($dateModifiedParsed) {
+ $date = new DateTime('@' . $dateModifiedParsed);
+ } else {
+ $dateStandards = array(DateTime::RSS, DateTime::RFC822,
+ DateTime::RFC2822, null);
+ foreach ($dateStandards as $standard) {
+ try {
+ $date = DateTime::createFromFormat($standard, $dateModified);
+ break;
+ } catch (\Exception $e) {
+ if ($standard == null) {
+ throw new Exception\RuntimeException(
+ 'Could not load date due to unrecognised'
+ .' format (should follow RFC 822 or 2822):'
+ . $e->getMessage(),
+ 0, $e
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!$date) {
+ $date = $this->getExtension('DublinCore')->getDate();
+ }
+
+ if (!$date) {
+ $date = $this->getExtension('Atom')->getDateModified();
+ }
+
+ if (!$date) {
+ $date = null;
+ }
+
+ $this->data['datemodified'] = $date;
+
+ return $this->data['datemodified'];
+ }
+
+ /**
+ * Get the feed lastBuild date
+ *
+ * @throws Exception\RuntimeException
+ * @return DateTime
+ */
+ public function getLastBuildDate()
+ {
+ if (array_key_exists('lastBuildDate', $this->data)) {
+ return $this->data['lastBuildDate'];
+ }
+
+ $lastBuildDate = null;
+ $date = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $lastBuildDate = $this->xpath->evaluate('string(/rss/channel/lastBuildDate)');
+ if ($lastBuildDate) {
+ $lastBuildDateParsed = strtotime($lastBuildDate);
+ if ($lastBuildDateParsed) {
+ $date = new DateTime('@' . $lastBuildDateParsed);
+ } else {
+ $dateStandards = array(DateTime::RSS, DateTime::RFC822,
+ DateTime::RFC2822, null);
+ foreach ($dateStandards as $standard) {
+ try {
+ $date = DateTime::createFromFormat($standard, $lastBuildDateParsed);
+ break;
+ } catch (\Exception $e) {
+ if ($standard == null) {
+ throw new Exception\RuntimeException(
+ 'Could not load date due to unrecognised'
+ .' format (should follow RFC 822 or 2822):'
+ . $e->getMessage(),
+ 0, $e
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!$date) {
+ $date = null;
+ }
+
+ $this->data['lastBuildDate'] = $date;
+
+ return $this->data['lastBuildDate'];
+ }
+
+ /**
+ * Get the feed description
+ *
+ * @return string|null
+ */
+ public function getDescription()
+ {
+ if (array_key_exists('description', $this->data)) {
+ return $this->data['description'];
+ }
+
+ $description = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $description = $this->xpath->evaluate('string(/rss/channel/description)');
+ } else {
+ $description = $this->xpath->evaluate('string(/rdf:RDF/rss:channel/rss:description)');
+ }
+
+ if (!$description && $this->getExtension('DublinCore') !== null) {
+ $description = $this->getExtension('DublinCore')->getDescription();
+ }
+
+ if (empty($description)) {
+ $description = $this->getExtension('Atom')->getDescription();
+ }
+
+ if (!$description) {
+ $description = null;
+ }
+
+ $this->data['description'] = $description;
+
+ return $this->data['description'];
+ }
+
+ /**
+ * Get the feed ID
+ *
+ * @return string|null
+ */
+ public function getId()
+ {
+ if (array_key_exists('id', $this->data)) {
+ return $this->data['id'];
+ }
+
+ $id = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $id = $this->xpath->evaluate('string(/rss/channel/guid)');
+ }
+
+ if (!$id && $this->getExtension('DublinCore') !== null) {
+ $id = $this->getExtension('DublinCore')->getId();
+ }
+
+ if (empty($id)) {
+ $id = $this->getExtension('Atom')->getId();
+ }
+
+ if (!$id) {
+ if ($this->getLink()) {
+ $id = $this->getLink();
+ } elseif ($this->getTitle()) {
+ $id = $this->getTitle();
+ } else {
+ $id = null;
+ }
+ }
+
+ $this->data['id'] = $id;
+
+ return $this->data['id'];
+ }
+
+ /**
+ * Get the feed image data
+ *
+ * @return array|null
+ */
+ public function getImage()
+ {
+ if (array_key_exists('image', $this->data)) {
+ return $this->data['image'];
+ }
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $list = $this->xpath->query('/rss/channel/image');
+ $prefix = '/rss/channel/image[1]';
+ } else {
+ $list = $this->xpath->query('/rdf:RDF/rss:channel/rss:image');
+ $prefix = '/rdf:RDF/rss:channel/rss:image[1]';
+ }
+ if ($list->length > 0) {
+ $image = array();
+ $value = $this->xpath->evaluate('string(' . $prefix . '/url)');
+ if ($value) {
+ $image['uri'] = $value;
+ }
+ $value = $this->xpath->evaluate('string(' . $prefix . '/link)');
+ if ($value) {
+ $image['link'] = $value;
+ }
+ $value = $this->xpath->evaluate('string(' . $prefix . '/title)');
+ if ($value) {
+ $image['title'] = $value;
+ }
+ $value = $this->xpath->evaluate('string(' . $prefix . '/height)');
+ if ($value) {
+ $image['height'] = $value;
+ }
+ $value = $this->xpath->evaluate('string(' . $prefix . '/width)');
+ if ($value) {
+ $image['width'] = $value;
+ }
+ $value = $this->xpath->evaluate('string(' . $prefix . '/description)');
+ if ($value) {
+ $image['description'] = $value;
+ }
+ } else {
+ $image = null;
+ }
+
+ $this->data['image'] = $image;
+
+ return $this->data['image'];
+ }
+
+ /**
+ * Get the feed language
+ *
+ * @return string|null
+ */
+ public function getLanguage()
+ {
+ if (array_key_exists('language', $this->data)) {
+ return $this->data['language'];
+ }
+
+ $language = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $language = $this->xpath->evaluate('string(/rss/channel/language)');
+ }
+
+ if (!$language && $this->getExtension('DublinCore') !== null) {
+ $language = $this->getExtension('DublinCore')->getLanguage();
+ }
+
+ if (empty($language)) {
+ $language = $this->getExtension('Atom')->getLanguage();
+ }
+
+ if (!$language) {
+ $language = $this->xpath->evaluate('string(//@xml:lang[1])');
+ }
+
+ if (!$language) {
+ $language = null;
+ }
+
+ $this->data['language'] = $language;
+
+ return $this->data['language'];
+ }
+
+ /**
+ * Get a link to the feed
+ *
+ * @return string|null
+ */
+ public function getLink()
+ {
+ if (array_key_exists('link', $this->data)) {
+ return $this->data['link'];
+ }
+
+ $link = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $link = $this->xpath->evaluate('string(/rss/channel/link)');
+ } else {
+ $link = $this->xpath->evaluate('string(/rdf:RDF/rss:channel/rss:link)');
+ }
+
+ if (empty($link)) {
+ $link = $this->getExtension('Atom')->getLink();
+ }
+
+ if (!$link) {
+ $link = null;
+ }
+
+ $this->data['link'] = $link;
+
+ return $this->data['link'];
+ }
+
+ /**
+ * Get a link to the feed XML
+ *
+ * @return string|null
+ */
+ public function getFeedLink()
+ {
+ if (array_key_exists('feedlink', $this->data)) {
+ return $this->data['feedlink'];
+ }
+
+ $link = null;
+
+ $link = $this->getExtension('Atom')->getFeedLink();
+
+ if ($link === null || empty($link)) {
+ $link = $this->getOriginalSourceUri();
+ }
+
+ $this->data['feedlink'] = $link;
+
+ return $this->data['feedlink'];
+ }
+
+ /**
+ * Get the feed generator entry
+ *
+ * @return string|null
+ */
+ public function getGenerator()
+ {
+ if (array_key_exists('generator', $this->data)) {
+ return $this->data['generator'];
+ }
+
+ $generator = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $generator = $this->xpath->evaluate('string(/rss/channel/generator)');
+ }
+
+ if (!$generator) {
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $generator = $this->xpath->evaluate('string(/rss/channel/atom:generator)');
+ } else {
+ $generator = $this->xpath->evaluate('string(/rdf:RDF/rss:channel/atom:generator)');
+ }
+ }
+
+ if (empty($generator)) {
+ $generator = $this->getExtension('Atom')->getGenerator();
+ }
+
+ if (!$generator) {
+ $generator = null;
+ }
+
+ $this->data['generator'] = $generator;
+
+ return $this->data['generator'];
+ }
+
+ /**
+ * Get the feed title
+ *
+ * @return string|null
+ */
+ public function getTitle()
+ {
+ if (array_key_exists('title', $this->data)) {
+ return $this->data['title'];
+ }
+
+ $title = null;
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $title = $this->xpath->evaluate('string(/rss/channel/title)');
+ } else {
+ $title = $this->xpath->evaluate('string(/rdf:RDF/rss:channel/rss:title)');
+ }
+
+ if (!$title && $this->getExtension('DublinCore') !== null) {
+ $title = $this->getExtension('DublinCore')->getTitle();
+ }
+
+ if (!$title) {
+ $title = $this->getExtension('Atom')->getTitle();
+ }
+
+ if (!$title) {
+ $title = null;
+ }
+
+ $this->data['title'] = $title;
+
+ return $this->data['title'];
+ }
+
+ /**
+ * Get an array of any supported Pusubhubbub endpoints
+ *
+ * @return array|null
+ */
+ public function getHubs()
+ {
+ if (array_key_exists('hubs', $this->data)) {
+ return $this->data['hubs'];
+ }
+
+ $hubs = $this->getExtension('Atom')->getHubs();
+
+ if (empty($hubs)) {
+ $hubs = null;
+ } else {
+ $hubs = array_unique($hubs);
+ }
+
+ $this->data['hubs'] = $hubs;
+
+ return $this->data['hubs'];
+ }
+
+ /**
+ * Get all categories
+ *
+ * @return Reader\Collection\Category
+ */
+ public function getCategories()
+ {
+ if (array_key_exists('categories', $this->data)) {
+ return $this->data['categories'];
+ }
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
+ $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $list = $this->xpath->query('/rss/channel//category');
+ } else {
+ $list = $this->xpath->query('/rdf:RDF/rss:channel//rss:category');
+ }
+
+ if ($list->length) {
+ $categoryCollection = new Collection\Category;
+ foreach ($list as $category) {
+ $categoryCollection[] = array(
+ 'term' => $category->nodeValue,
+ 'scheme' => $category->getAttribute('domain'),
+ 'label' => $category->nodeValue,
+ );
+ }
+ } else {
+ $categoryCollection = $this->getExtension('DublinCore')->getCategories();
+ }
+
+ if (count($categoryCollection) == 0) {
+ $categoryCollection = $this->getExtension('Atom')->getCategories();
+ }
+
+ $this->data['categories'] = $categoryCollection;
+
+ return $this->data['categories'];
+ }
+
+ /**
+ * Read all entries to the internal entries array
+ *
+ */
+ protected function indexEntries()
+ {
+ $entries = array();
+
+ if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && $this->getType() !== Reader\Reader::TYPE_RSS_090) {
+ $entries = $this->xpath->evaluate('//item');
+ } else {
+ $entries = $this->xpath->evaluate('//rss:item');
+ }
+
+ foreach ($entries as $index => $entry) {
+ $this->entries[$index] = $entry;
+ }
+ }
+
+ /**
+ * Register the default namespaces for the current feed format
+ *
+ */
+ protected function registerNamespaces()
+ {
+ switch ($this->data['type']) {
+ case Reader\Reader::TYPE_RSS_10:
+ $this->xpath->registerNamespace('rdf', Reader\Reader::NAMESPACE_RDF);
+ $this->xpath->registerNamespace('rss', Reader\Reader::NAMESPACE_RSS_10);
+ break;
+
+ case Reader\Reader::TYPE_RSS_090:
+ $this->xpath->registerNamespace('rdf', Reader\Reader::NAMESPACE_RDF);
+ $this->xpath->registerNamespace('rss', Reader\Reader::NAMESPACE_RSS_090);
+ break;
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/FeedSet.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/FeedSet.php
new file mode 100644
index 0000000..c947620
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/FeedSet.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader;
+
+use ArrayObject;
+use DOMNodeList;
+use Zend\Feed\Uri;
+
+/**
+*/
+class FeedSet extends ArrayObject
+{
+
+ public $rss = null;
+
+ public $rdf = null;
+
+ public $atom = null;
+
+ /**
+ * Import a DOMNodeList from any document containing a set of links
+ * for alternate versions of a document, which will normally refer to
+ * RSS/RDF/Atom feeds for the current document.
+ *
+ * All such links are stored internally, however the first instance of
+ * each RSS, RDF or Atom type has its URI stored as a public property
+ * as a shortcut where the use case is simply to get a quick feed ref.
+ *
+ * Note that feeds are not loaded at this point, but will be lazy
+ * loaded automatically when each links 'feed' array key is accessed.
+ *
+ * @param DOMNodeList $links
+ * @param string $uri
+ * @return void
+ */
+ public function addLinks(DOMNodeList $links, $uri)
+ {
+ foreach ($links as $link) {
+ if (strtolower($link->getAttribute('rel')) !== 'alternate'
+ || !$link->getAttribute('type') || !$link->getAttribute('href')) {
+ continue;
+ }
+ if (!isset($this->rss) && $link->getAttribute('type') == 'application/rss+xml') {
+ $this->rss = $this->absolutiseUri(trim($link->getAttribute('href')), $uri);
+ } elseif (!isset($this->atom) && $link->getAttribute('type') == 'application/atom+xml') {
+ $this->atom = $this->absolutiseUri(trim($link->getAttribute('href')), $uri);
+ } elseif (!isset($this->rdf) && $link->getAttribute('type') == 'application/rdf+xml') {
+ $this->rdf = $this->absolutiseUri(trim($link->getAttribute('href')), $uri);
+ }
+ $this[] = new static(array(
+ 'rel' => 'alternate',
+ 'type' => $link->getAttribute('type'),
+ 'href' => $this->absolutiseUri(trim($link->getAttribute('href')), $uri),
+ ));
+ }
+ }
+
+ /**
+ * Attempt to turn a relative URI into an absolute URI
+ */
+ protected function absolutiseUri($link, $uri = null)
+ {
+ $linkUri = Uri::factory($link);
+ if (!$linkUri->isAbsolute() or !$linkUri->isValid()) {
+ if ($uri !== null) {
+ $uri = Uri::factory($uri);
+
+ if ($link[0] !== '/') {
+ $link = $uri->getPath() . '/' . $link;
+ }
+
+ $link = $uri->getScheme() . '://' . $uri->getHost() . '/' . $this->canonicalizePath($link);
+ if (!Uri::factory($link)->isValid()) {
+ $link = null;
+ }
+ }
+ }
+ return $link;
+ }
+
+ /**
+ * Canonicalize relative path
+ */
+ protected function canonicalizePath($path)
+ {
+ $parts = array_filter(explode('/', $path));
+ $absolutes = array();
+ foreach ($parts as $part) {
+ if ('.' == $part) {
+ continue;
+ }
+ if ('..' == $part) {
+ array_pop($absolutes);
+ } else {
+ $absolutes[] = $part;
+ }
+ }
+ return implode('/', $absolutes);
+ }
+
+ /**
+ * Supports lazy loading of feeds using Reader::import() but
+ * delegates any other operations to the parent class.
+ *
+ * @param string $offset
+ * @return mixed
+ */
+ public function offsetGet($offset)
+ {
+ if ($offset == 'feed' && !$this->offsetExists('feed')) {
+ if (!$this->offsetExists('href')) {
+ return null;
+ }
+ $feed = Reader::import($this->offsetGet('href'));
+ $this->offsetSet('feed', $feed);
+ return $feed;
+ }
+ return parent::offsetGet($offset);
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Http/ClientInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Http/ClientInterface.php
new file mode 100644
index 0000000..dc0f5f6
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Http/ClientInterface.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Http;
+
+interface ClientInterface
+{
+ /**
+ * Make a GET request to a given URI
+ *
+ * @param string $uri
+ * @return ResponseInterface
+ */
+ public function get($uri);
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Http/ResponseInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Http/ResponseInterface.php
new file mode 100644
index 0000000..5027f20
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Http/ResponseInterface.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader\Http;
+
+interface ResponseInterface
+{
+ /**
+ * Retrieve the response body
+ *
+ * @return string
+ */
+ public function getBody();
+
+ /**
+ * Retrieve the HTTP response status code
+ *
+ * @return int
+ */
+ public function getStatusCode();
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Reader.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Reader.php
new file mode 100644
index 0000000..7f8a25c
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Reader/Reader.php
@@ -0,0 +1,674 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Reader;
+
+use DOMDocument;
+use DOMXPath;
+use Zend\Cache\Storage\StorageInterface as CacheStorage;
+use Zend\Http as ZendHttp;
+use Zend\Stdlib\ErrorHandler;
+
+/**
+*/
+class Reader
+{
+ /**
+ * Namespace constants
+ */
+ const NAMESPACE_ATOM_03 = 'http://purl.org/atom/ns#';
+ const NAMESPACE_ATOM_10 = 'http://www.w3.org/2005/Atom';
+ const NAMESPACE_RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+ const NAMESPACE_RSS_090 = 'http://my.netscape.com/rdf/simple/0.9/';
+ const NAMESPACE_RSS_10 = 'http://purl.org/rss/1.0/';
+
+ /**
+ * Feed type constants
+ */
+ const TYPE_ANY = 'any';
+ const TYPE_ATOM_03 = 'atom-03';
+ const TYPE_ATOM_10 = 'atom-10';
+ const TYPE_ATOM_10_ENTRY = 'atom-10-entry';
+ const TYPE_ATOM_ANY = 'atom';
+ const TYPE_RSS_090 = 'rss-090';
+ const TYPE_RSS_091 = 'rss-091';
+ const TYPE_RSS_091_NETSCAPE = 'rss-091n';
+ const TYPE_RSS_091_USERLAND = 'rss-091u';
+ const TYPE_RSS_092 = 'rss-092';
+ const TYPE_RSS_093 = 'rss-093';
+ const TYPE_RSS_094 = 'rss-094';
+ const TYPE_RSS_10 = 'rss-10';
+ const TYPE_RSS_20 = 'rss-20';
+ const TYPE_RSS_ANY = 'rss';
+
+ /**
+ * Cache instance
+ *
+ * @var CacheStorage
+ */
+ protected static $cache = null;
+
+ /**
+ * HTTP client object to use for retrieving feeds
+ *
+ * @var ZendHttp\Client
+ */
+ protected static $httpClient = null;
+
+ /**
+ * Override HTTP PUT and DELETE request methods?
+ *
+ * @var bool
+ */
+ protected static $httpMethodOverride = false;
+
+ protected static $httpConditionalGet = false;
+
+ protected static $extensionManager = null;
+
+ protected static $extensions = array(
+ 'feed' => array(
+ 'DublinCore\Feed',
+ 'Atom\Feed'
+ ),
+ 'entry' => array(
+ 'Content\Entry',
+ 'DublinCore\Entry',
+ 'Atom\Entry'
+ ),
+ 'core' => array(
+ 'DublinCore\Feed',
+ 'Atom\Feed',
+ 'Content\Entry',
+ 'DublinCore\Entry',
+ 'Atom\Entry'
+ )
+ );
+
+ /**
+ * Get the Feed cache
+ *
+ * @return CacheStorage
+ */
+ public static function getCache()
+ {
+ return static::$cache;
+ }
+
+ /**
+ * Set the feed cache
+ *
+ * @param CacheStorage $cache
+ * @return void
+ */
+ public static function setCache(CacheStorage $cache)
+ {
+ static::$cache = $cache;
+ }
+
+ /**
+ * Set the HTTP client instance
+ *
+ * Sets the HTTP client object to use for retrieving the feeds.
+ *
+ * @param ZendHttp\Client $httpClient
+ * @return void
+ */
+ public static function setHttpClient(ZendHttp\Client $httpClient)
+ {
+ static::$httpClient = $httpClient;
+ }
+
+
+ /**
+ * Gets the HTTP client object. If none is set, a new ZendHttp\Client will be used.
+ *
+ * @return ZendHttp\Client
+ */
+ public static function getHttpClient()
+ {
+ if (!static::$httpClient instanceof ZendHttp\Client) {
+ static::$httpClient = new ZendHttp\Client();
+ }
+
+ return static::$httpClient;
+ }
+
+ /**
+ * Toggle using POST instead of PUT and DELETE HTTP methods
+ *
+ * Some feed implementations do not accept PUT and DELETE HTTP
+ * methods, or they can't be used because of proxies or other
+ * measures. This allows turning on using POST where PUT and
+ * DELETE would normally be used; in addition, an
+ * X-Method-Override header will be sent with a value of PUT or
+ * DELETE as appropriate.
+ *
+ * @param bool $override Whether to override PUT and DELETE.
+ * @return void
+ */
+ public static function setHttpMethodOverride($override = true)
+ {
+ static::$httpMethodOverride = $override;
+ }
+
+ /**
+ * Get the HTTP override state
+ *
+ * @return bool
+ */
+ public static function getHttpMethodOverride()
+ {
+ return static::$httpMethodOverride;
+ }
+
+ /**
+ * Set the flag indicating whether or not to use HTTP conditional GET
+ *
+ * @param bool $bool
+ * @return void
+ */
+ public static function useHttpConditionalGet($bool = true)
+ {
+ static::$httpConditionalGet = $bool;
+ }
+
+ /**
+ * Import a feed by providing a URI
+ *
+ * @param string $uri The URI to the feed
+ * @param string $etag OPTIONAL Last received ETag for this resource
+ * @param string $lastModified OPTIONAL Last-Modified value for this resource
+ * @return Feed\FeedInterface
+ * @throws Exception\RuntimeException
+ */
+ public static function import($uri, $etag = null, $lastModified = null)
+ {
+ $cache = self::getCache();
+ $feed = null;
+ $responseXml = '';
+ $client = self::getHttpClient();
+ $client->resetParameters();
+ $headers = new ZendHttp\Headers();
+ $client->setHeaders($headers);
+ $client->setUri($uri);
+ $cacheId = 'Zend_Feed_Reader_' . md5($uri);
+
+ if (static::$httpConditionalGet && $cache) {
+ $data = $cache->getItem($cacheId);
+ if ($data) {
+ if ($etag === null) {
+ $etag = $cache->getItem($cacheId . '_etag');
+ }
+ if ($lastModified === null) {
+ $lastModified = $cache->getItem($cacheId . '_lastmodified');
+ }
+ if ($etag) {
+ $headers->addHeaderLine('If-None-Match', $etag);
+ }
+ if ($lastModified) {
+ $headers->addHeaderLine('If-Modified-Since', $lastModified);
+ }
+ }
+ $response = $client->send();
+ if ($response->getStatusCode() !== 200 && $response->getStatusCode() !== 304) {
+ throw new Exception\RuntimeException('Feed failed to load, got response code ' . $response->getStatusCode());
+ }
+ if ($response->getStatusCode() == 304) {
+ $responseXml = $data;
+ } else {
+ $responseXml = $response->getBody();
+ $cache->setItem($cacheId, $responseXml);
+ if ($response->getHeaders()->get('ETag')) {
+ $cache->setItem($cacheId . '_etag', $response->getHeaders()->get('ETag')->getFieldValue());
+ }
+ if ($response->getHeaders()->get('Last-Modified')) {
+ $cache->setItem($cacheId . '_lastmodified', $response->getHeaders()->get('Last-Modified')->getFieldValue());
+ }
+ }
+ return static::importString($responseXml);
+ } elseif ($cache) {
+ $data = $cache->getItem($cacheId);
+ if ($data) {
+ return static::importString($data);
+ }
+ $response = $client->send();
+ if ((int) $response->getStatusCode() !== 200) {
+ throw new Exception\RuntimeException('Feed failed to load, got response code ' . $response->getStatusCode());
+ }
+ $responseXml = $response->getBody();
+ $cache->setItem($cacheId, $responseXml);
+ return static::importString($responseXml);
+ } else {
+ $response = $client->send();
+ if ((int) $response->getStatusCode() !== 200) {
+ throw new Exception\RuntimeException('Feed failed to load, got response code ' . $response->getStatusCode());
+ }
+ $reader = static::importString($response->getBody());
+ $reader->setOriginalSourceUri($uri);
+ return $reader;
+ }
+ }
+
+ /**
+ * Import a feed from a remote URI
+ *
+ * Performs similarly to import(), except it uses the HTTP client passed to
+ * the method, and does not take into account cached data.
+ *
+ * Primary purpose is to make it possible to use the Reader with alternate
+ * HTTP client implementations.
+ *
+ * @param string $uri
+ * @param Http\Client $client
+ * @return self
+ * @throws Exception\RuntimeException if response is not an Http\ResponseInterface
+ */
+ public static function importRemoteFeed($uri, Http\ClientInterface $client)
+ {
+ $response = $client->get($uri);
+ if (!$response instanceof Http\ResponseInterface) {
+ throw new Exception\RuntimeException(sprintf(
+ 'Did not receive a %s\Http\ResponseInterface from the provided HTTP client; received "%s"',
+ __NAMESPACE__,
+ (is_object($response) ? get_class($response) : gettype($response))
+ ));
+ }
+
+ if ((int) $response->getStatusCode() !== 200) {
+ throw new Exception\RuntimeException('Feed failed to load, got response code ' . $response->getStatusCode());
+ }
+ $reader = static::importString($response->getBody());
+ $reader->setOriginalSourceUri($uri);
+ return $reader;
+ }
+
+ /**
+ * Import a feed from a string
+ *
+ * @param string $string
+ * @return Feed\FeedInterface
+ * @throws Exception\InvalidArgumentException
+ * @throws Exception\RuntimeException
+ */
+ public static function importString($string)
+ {
+ $libxmlErrflag = libxml_use_internal_errors(true);
+ $oldValue = libxml_disable_entity_loader(true);
+ $dom = new DOMDocument;
+ $status = $dom->loadXML(trim($string));
+ foreach ($dom->childNodes as $child) {
+ if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
+ throw new Exception\InvalidArgumentException(
+ 'Invalid XML: Detected use of illegal DOCTYPE'
+ );
+ }
+ }
+ libxml_disable_entity_loader($oldValue);
+ libxml_use_internal_errors($libxmlErrflag);
+
+ if (!$status) {
+ // Build error message
+ $error = libxml_get_last_error();
+ if ($error && $error->message) {
+ $error->message = trim($error->message);
+ $errormsg = "DOMDocument cannot parse XML: {$error->message}";
+ } else {
+ $errormsg = "DOMDocument cannot parse XML: Please check the XML document's validity";
+ }
+ throw new Exception\RuntimeException($errormsg);
+ }
+
+ $type = static::detectType($dom);
+
+ static::registerCoreExtensions();
+
+ if (substr($type, 0, 3) == 'rss') {
+ $reader = new Feed\Rss($dom, $type);
+ } elseif (substr($type, 8, 5) == 'entry') {
+ $reader = new Entry\Atom($dom->documentElement, 0, self::TYPE_ATOM_10);
+ } elseif (substr($type, 0, 4) == 'atom') {
+ $reader = new Feed\Atom($dom, $type);
+ } else {
+ throw new Exception\RuntimeException('The URI used does not point to a '
+ . 'valid Atom, RSS or RDF feed that Zend\Feed\Reader can parse.');
+ }
+ return $reader;
+ }
+
+ /**
+ * Imports a feed from a file located at $filename.
+ *
+ * @param string $filename
+ * @throws Exception\RuntimeException
+ * @return Feed\FeedInterface
+ */
+ public static function importFile($filename)
+ {
+ ErrorHandler::start();
+ $feed = file_get_contents($filename);
+ $err = ErrorHandler::stop();
+ if ($feed === false) {
+ throw new Exception\RuntimeException("File '{$filename}' could not be loaded", 0, $err);
+ }
+ return static::importString($feed);
+ }
+
+ /**
+ * Find feed links
+ *
+ * @param $uri
+ * @return FeedSet
+ * @throws Exception\RuntimeException
+ */
+ public static function findFeedLinks($uri)
+ {
+ $client = static::getHttpClient();
+ $client->setUri($uri);
+ $response = $client->send();
+ if ($response->getStatusCode() !== 200) {
+ throw new Exception\RuntimeException("Failed to access $uri, got response code " . $response->getStatusCode());
+ }
+ $responseHtml = $response->getBody();
+ $libxmlErrflag = libxml_use_internal_errors(true);
+ $oldValue = libxml_disable_entity_loader(true);
+ $dom = new DOMDocument;
+ $status = $dom->loadHTML(trim($responseHtml));
+ libxml_disable_entity_loader($oldValue);
+ libxml_use_internal_errors($libxmlErrflag);
+ if (!$status) {
+ // Build error message
+ $error = libxml_get_last_error();
+ if ($error && $error->message) {
+ $error->message = trim($error->message);
+ $errormsg = "DOMDocument cannot parse HTML: {$error->message}";
+ } else {
+ $errormsg = "DOMDocument cannot parse HTML: Please check the XML document's validity";
+ }
+ throw new Exception\RuntimeException($errormsg);
+ }
+ $feedSet = new FeedSet;
+ $links = $dom->getElementsByTagName('link');
+ $feedSet->addLinks($links, $uri);
+ return $feedSet;
+ }
+
+ /**
+ * Detect the feed type of the provided feed
+ *
+ * @param Feed\AbstractFeed|DOMDocument|string $feed
+ * @param bool $specOnly
+ * @return string
+ * @throws Exception\InvalidArgumentException
+ * @throws Exception\RuntimeException
+ */
+ public static function detectType($feed, $specOnly = false)
+ {
+ if ($feed instanceof Feed\AbstractFeed) {
+ $dom = $feed->getDomDocument();
+ } elseif ($feed instanceof DOMDocument) {
+ $dom = $feed;
+ } elseif (is_string($feed) && !empty($feed)) {
+ ErrorHandler::start(E_NOTICE|E_WARNING);
+ ini_set('track_errors', 1);
+ $oldValue = libxml_disable_entity_loader(true);
+ $dom = new DOMDocument;
+ $status = $dom->loadXML($feed);
+ foreach ($dom->childNodes as $child) {
+ if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
+ throw new Exception\InvalidArgumentException(
+ 'Invalid XML: Detected use of illegal DOCTYPE'
+ );
+ }
+ }
+ libxml_disable_entity_loader($oldValue);
+ ini_restore('track_errors');
+ ErrorHandler::stop();
+ if (!$status) {
+ if (!isset($phpErrormsg)) {
+ if (function_exists('xdebug_is_enabled')) {
+ $phpErrormsg = '(error message not available, when XDebug is running)';
+ } else {
+ $phpErrormsg = '(error message not available)';
+ }
+ }
+ throw new Exception\RuntimeException("DOMDocument cannot parse XML: $phpErrormsg");
+ }
+ } else {
+ throw new Exception\InvalidArgumentException('Invalid object/scalar provided: must'
+ . ' be of type Zend\Feed\Reader\Feed, DomDocument or string');
+ }
+ $xpath = new DOMXPath($dom);
+
+ if ($xpath->query('/rss')->length) {
+ $type = self::TYPE_RSS_ANY;
+ $version = $xpath->evaluate('string(/rss/@version)');
+
+ if (strlen($version) > 0) {
+ switch ($version) {
+ case '2.0':
+ $type = self::TYPE_RSS_20;
+ break;
+
+ case '0.94':
+ $type = self::TYPE_RSS_094;
+ break;
+
+ case '0.93':
+ $type = self::TYPE_RSS_093;
+ break;
+
+ case '0.92':
+ $type = self::TYPE_RSS_092;
+ break;
+
+ case '0.91':
+ $type = self::TYPE_RSS_091;
+ break;
+ }
+ }
+
+ return $type;
+ }
+
+ $xpath->registerNamespace('rdf', self::NAMESPACE_RDF);
+
+ if ($xpath->query('/rdf:RDF')->length) {
+ $xpath->registerNamespace('rss', self::NAMESPACE_RSS_10);
+
+ if ($xpath->query('/rdf:RDF/rss:channel')->length
+ || $xpath->query('/rdf:RDF/rss:image')->length
+ || $xpath->query('/rdf:RDF/rss:item')->length
+ || $xpath->query('/rdf:RDF/rss:textinput')->length
+ ) {
+ return self::TYPE_RSS_10;
+ }
+
+ $xpath->registerNamespace('rss', self::NAMESPACE_RSS_090);
+
+ if ($xpath->query('/rdf:RDF/rss:channel')->length
+ || $xpath->query('/rdf:RDF/rss:image')->length
+ || $xpath->query('/rdf:RDF/rss:item')->length
+ || $xpath->query('/rdf:RDF/rss:textinput')->length
+ ) {
+ return self::TYPE_RSS_090;
+ }
+ }
+
+ $xpath->registerNamespace('atom', self::NAMESPACE_ATOM_10);
+
+ if ($xpath->query('//atom:feed')->length) {
+ return self::TYPE_ATOM_10;
+ }
+
+ if ($xpath->query('//atom:entry')->length) {
+ if ($specOnly == true) {
+ return self::TYPE_ATOM_10;
+ } else {
+ return self::TYPE_ATOM_10_ENTRY;
+ }
+ }
+
+ $xpath->registerNamespace('atom', self::NAMESPACE_ATOM_03);
+
+ if ($xpath->query('//atom:feed')->length) {
+ return self::TYPE_ATOM_03;
+ }
+
+ return self::TYPE_ANY;
+ }
+
+ /**
+ * Set plugin manager for use with Extensions
+ *
+ * @param ExtensionManagerInterface $extensionManager
+ */
+ public static function setExtensionManager(ExtensionManagerInterface $extensionManager)
+ {
+ static::$extensionManager = $extensionManager;
+ }
+
+ /**
+ * Get plugin manager for use with Extensions
+ *
+ * @return ExtensionManagerInterface
+ */
+ public static function getExtensionManager()
+ {
+ if (!isset(static::$extensionManager)) {
+ static::setExtensionManager(new ExtensionManager());
+ }
+ return static::$extensionManager;
+ }
+
+ /**
+ * Register an Extension by name
+ *
+ * @param string $name
+ * @return void
+ * @throws Exception\RuntimeException if unable to resolve Extension class
+ */
+ public static function registerExtension($name)
+ {
+ $feedName = $name . '\Feed';
+ $entryName = $name . '\Entry';
+ $manager = static::getExtensionManager();
+ if (static::isRegistered($name)) {
+ if ($manager->has($feedName) || $manager->has($entryName)) {
+ return;
+ }
+ }
+
+ if (!$manager->has($feedName) && !$manager->has($entryName)) {
+ throw new Exception\RuntimeException('Could not load extension: ' . $name
+ . ' using Plugin Loader. Check prefix paths are configured and extension exists.');
+ }
+ if ($manager->has($feedName)) {
+ static::$extensions['feed'][] = $feedName;
+ }
+ if ($manager->has($entryName)) {
+ static::$extensions['entry'][] = $entryName;
+ }
+ }
+
+ /**
+ * Is a given named Extension registered?
+ *
+ * @param string $extensionName
+ * @return bool
+ */
+ public static function isRegistered($extensionName)
+ {
+ $feedName = $extensionName . '\Feed';
+ $entryName = $extensionName . '\Entry';
+ if (in_array($feedName, static::$extensions['feed'])
+ || in_array($entryName, static::$extensions['entry'])
+ ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get a list of extensions
+ *
+ * @return array
+ */
+ public static function getExtensions()
+ {
+ return static::$extensions;
+ }
+
+ /**
+ * Reset class state to defaults
+ *
+ * @return void
+ */
+ public static function reset()
+ {
+ static::$cache = null;
+ static::$httpClient = null;
+ static::$httpMethodOverride = false;
+ static::$httpConditionalGet = false;
+ static::$extensionManager = null;
+ static::$extensions = array(
+ 'feed' => array(
+ 'DublinCore\Feed',
+ 'Atom\Feed'
+ ),
+ 'entry' => array(
+ 'Content\Entry',
+ 'DublinCore\Entry',
+ 'Atom\Entry'
+ ),
+ 'core' => array(
+ 'DublinCore\Feed',
+ 'Atom\Feed',
+ 'Content\Entry',
+ 'DublinCore\Entry',
+ 'Atom\Entry'
+ )
+ );
+ }
+
+ /**
+ * Register core (default) extensions
+ *
+ * @return void
+ */
+ protected static function registerCoreExtensions()
+ {
+ static::registerExtension('DublinCore');
+ static::registerExtension('Content');
+ static::registerExtension('Atom');
+ static::registerExtension('Slash');
+ static::registerExtension('WellFormedWeb');
+ static::registerExtension('Thread');
+ static::registerExtension('Podcast');
+ }
+
+ /**
+ * Utility method to apply array_unique operation to a multidimensional
+ * array.
+ *
+ * @param array
+ * @return array
+ */
+ public static function arrayUnique(array $array)
+ {
+ foreach ($array as &$value) {
+ $value = serialize($value);
+ }
+ $array = array_unique($array);
+ foreach ($array as &$value) {
+ $value = unserialize($value);
+ }
+ return $array;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Uri.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Uri.php
new file mode 100644
index 0000000..c2403c5b
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Uri.php
@@ -0,0 +1,184 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed;
+
+class Uri
+{
+ /**
+ * @var string
+ */
+ protected $fragment;
+
+ /**
+ * @var string
+ */
+ protected $host;
+
+ /**
+ * @var string
+ */
+ protected $pass;
+
+ /**
+ * @var string
+ */
+ protected $path;
+
+ /**
+ * @var int
+ */
+ protected $port;
+
+ /**
+ * @var string
+ */
+ protected $query;
+
+ /**
+ * @var string
+ */
+ protected $scheme;
+
+ /**
+ * @var string
+ */
+ protected $user;
+
+ /**
+ * @var bool
+ */
+ protected $valid;
+
+ /**
+ * Valid schemes
+ */
+ protected $validSchemes = array(
+ 'http',
+ 'https',
+ 'file',
+ );
+
+ /**
+ * @param string $uri
+ */
+ public function __construct($uri)
+ {
+ $parsed = parse_url($uri);
+ if (false === $parsed) {
+ $this->valid = false;
+ return;
+ }
+
+ $this->scheme = isset($parsed['scheme']) ? $parsed['scheme'] : null;
+ $this->host = isset($parsed['host']) ? $parsed['host'] : null;
+ $this->port = isset($parsed['port']) ? $parsed['port'] : null;
+ $this->user = isset($parsed['user']) ? $parsed['user'] : null;
+ $this->pass = isset($parsed['pass']) ? $parsed['pass'] : null;
+ $this->path = isset($parsed['path']) ? $parsed['path'] : null;
+ $this->query = isset($parsed['query']) ? $parsed['query'] : null;
+ $this->fragment = isset($parsed['fragment']) ? $parsed['fragment'] : null;
+ }
+
+ /**
+ * Create an instance
+ *
+ * Useful for chained validations
+ *
+ * @param string $uri
+ * @return self
+ */
+ public static function factory($uri)
+ {
+ return new static($uri);
+ }
+
+ /**
+ * Retrieve the host
+ *
+ * @return string
+ */
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ /**
+ * Retrieve the URI path
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Retrieve the scheme
+ *
+ * @return string
+ */
+ public function getScheme()
+ {
+ return $this->scheme;
+ }
+
+ /**
+ * Is the URI valid?
+ *
+ * @return bool
+ */
+ public function isValid()
+ {
+ if (false === $this->valid) {
+ return false;
+ }
+
+ if ($this->scheme && !in_array($this->scheme, $this->validSchemes)) {
+ return false;
+ }
+
+ if ($this->host) {
+ if ($this->path && substr($this->path, 0, 1) != '/') {
+ return false;
+ }
+ return true;
+ }
+
+ // no host, but user and/or port... what?
+ if ($this->user || $this->port) {
+ return false;
+ }
+
+ if ($this->path) {
+ // Check path-only (no host) URI
+ if (substr($this->path, 0, 2) == '//') {
+ return false;
+ }
+ return true;
+ }
+
+ if (! ($this->query || $this->fragment)) {
+ // No host, path, query or fragment - this is not a valid URI
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Is the URI absolute?
+ *
+ * @return bool
+ */
+ public function isAbsolute()
+ {
+ return ($this->scheme !== null);
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/AbstractFeed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/AbstractFeed.php
new file mode 100644
index 0000000..389a987
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/AbstractFeed.php
@@ -0,0 +1,848 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer;
+
+use DateTime;
+use Zend\Feed\Uri;
+use Zend\Validator;
+
+class AbstractFeed
+{
+ /**
+ * Contains all Feed level date to append in feed output
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * Holds the value "atom" or "rss" depending on the feed type set when
+ * when last exported.
+ *
+ * @var string
+ */
+ protected $type = null;
+
+ /**
+ * @var $extensions
+ */
+ protected $extensions;
+
+ /**
+ * Constructor: Primarily triggers the registration of core extensions and
+ * loads those appropriate to this data container.
+ *
+ */
+ public function __construct()
+ {
+ Writer::registerCoreExtensions();
+ $this->_loadExtensions();
+ }
+
+ /**
+ * Set a single author
+ *
+ * The following option keys are supported:
+ * 'name' => (string) The name
+ * 'email' => (string) An optional email
+ * 'uri' => (string) An optional and valid URI
+ *
+ * @param array $author
+ * @throws Exception\InvalidArgumentException If any value of $author not follow the format.
+ * @return AbstractFeed
+ */
+ public function addAuthor(array $author)
+ {
+ // Check array values
+ if (!array_key_exists('name', $author)
+ || empty($author['name'])
+ || !is_string($author['name'])
+ ) {
+ throw new Exception\InvalidArgumentException(
+ 'Invalid parameter: author array must include a "name" key with a non-empty string value');
+ }
+
+ if (isset($author['email'])) {
+ if (empty($author['email']) || !is_string($author['email'])) {
+ throw new Exception\InvalidArgumentException(
+ 'Invalid parameter: "email" array value must be a non-empty string');
+ }
+ }
+ if (isset($author['uri'])) {
+ if (empty($author['uri']) || !is_string($author['uri']) ||
+ !Uri::factory($author['uri'])->isValid()
+ ) {
+ throw new Exception\InvalidArgumentException(
+ 'Invalid parameter: "uri" array value must be a non-empty string and valid URI/IRI');
+ }
+ }
+
+ $this->data['authors'][] = $author;
+
+ return $this;
+ }
+
+ /**
+ * Set an array with feed authors
+ *
+ * @see addAuthor
+ * @param array $authors
+ * @return AbstractFeed
+ */
+ public function addAuthors(array $authors)
+ {
+ foreach ($authors as $author) {
+ $this->addAuthor($author);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the copyright entry
+ *
+ * @param string $copyright
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setCopyright($copyright)
+ {
+ if (empty($copyright) || !is_string($copyright)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['copyright'] = $copyright;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed creation date
+ *
+ * @param null|int|DateTime
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setDateCreated($date = null)
+ {
+ if ($date === null) {
+ $date = new DateTime();
+ } elseif (is_int($date)) {
+ $date = new DateTime('@' . $date);
+ } elseif (!$date instanceof DateTime) {
+ throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp'
+ . ' passed as parameter');
+ }
+ $this->data['dateCreated'] = $date;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed modification date
+ *
+ * @param null|int|DateTime
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setDateModified($date = null)
+ {
+ if ($date === null) {
+ $date = new DateTime();
+ } elseif (is_int($date)) {
+ $date = new DateTime('@' . $date);
+ } elseif (!$date instanceof DateTime) {
+ throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp'
+ . ' passed as parameter');
+ }
+ $this->data['dateModified'] = $date;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed last-build date. Ignored for Atom 1.0.
+ *
+ * @param null|int|DateTime
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setLastBuildDate($date = null)
+ {
+ if ($date === null) {
+ $date = new DateTime();
+ } elseif (is_int($date)) {
+ $date = new DateTime('@' . $date);
+ } elseif (!$date instanceof DateTime) {
+ throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp'
+ . ' passed as parameter');
+ }
+ $this->data['lastBuildDate'] = $date;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed description
+ *
+ * @param string $description
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setDescription($description)
+ {
+ if (empty($description) || !is_string($description)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['description'] = $description;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed generator entry
+ *
+ * @param array|string $name
+ * @param null|string $version
+ * @param null|string $uri
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setGenerator($name, $version = null, $uri = null)
+ {
+ if (is_array($name)) {
+ $data = $name;
+ if (empty($data['name']) || !is_string($data['name'])) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "name" must be a non-empty string');
+ }
+ $generator = array('name' => $data['name']);
+ if (isset($data['version'])) {
+ if (empty($data['version']) || !is_string($data['version'])) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "version" must be a non-empty string');
+ }
+ $generator['version'] = $data['version'];
+ }
+ if (isset($data['uri'])) {
+ if (empty($data['uri']) || !is_string($data['uri']) || !Uri::factory($data['uri'])->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "uri" must be a non-empty string and a valid URI/IRI');
+ }
+ $generator['uri'] = $data['uri'];
+ }
+ } else {
+ if (empty($name) || !is_string($name)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "name" must be a non-empty string');
+ }
+ $generator = array('name' => $name);
+ if (isset($version)) {
+ if (empty($version) || !is_string($version)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "version" must be a non-empty string');
+ }
+ $generator['version'] = $version;
+ }
+ if (isset($uri)) {
+ if (empty($uri) || !is_string($uri) || !Uri::factory($uri)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "uri" must be a non-empty string and a valid URI/IRI');
+ }
+ $generator['uri'] = $uri;
+ }
+ }
+ $this->data['generator'] = $generator;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed ID - URI or URN (via PCRE pattern) supported
+ *
+ * @param string $id
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setId($id)
+ {
+ if ((empty($id) || !is_string($id) || !Uri::factory($id)->isValid())
+ && !preg_match("#^urn:[a-zA-Z0-9][a-zA-Z0-9\-]{1,31}:([a-zA-Z0-9\(\)\+\,\.\:\=\@\;\$\_\!\*\-]|%[0-9a-fA-F]{2})*#", $id)
+ && !$this->_validateTagUri($id)
+ ) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string and valid URI/IRI');
+ }
+ $this->data['id'] = $id;
+
+ return $this;
+ }
+
+ /**
+ * Validate a URI using the tag scheme (RFC 4151)
+ *
+ * @param string $id
+ * @return bool
+ */
+ protected function _validateTagUri($id)
+ {
+ if (preg_match('/^tag:(?P<name>.*),(?P<date>\d{4}-?\d{0,2}-?\d{0,2}):(?P<specific>.*)(.*:)*$/', $id, $matches)) {
+ $dvalid = false;
+ $nvalid = false;
+ $date = $matches['date'];
+ $d6 = strtotime($date);
+ if ((strlen($date) == 4) && $date <= date('Y')) {
+ $dvalid = true;
+ } elseif ((strlen($date) == 7) && ($d6 < strtotime("now"))) {
+ $dvalid = true;
+ } elseif ((strlen($date) == 10) && ($d6 < strtotime("now"))) {
+ $dvalid = true;
+ }
+ $validator = new Validator\EmailAddress;
+ if ($validator->isValid($matches['name'])) {
+ $nvalid = true;
+ } else {
+ $nvalid = $validator->isValid('info@' . $matches['name']);
+ }
+ return $dvalid && $nvalid;
+
+ }
+ return false;
+ }
+
+ /**
+ * Set a feed image (URI at minimum). Parameter is a single array with the
+ * required key 'uri'. When rendering as RSS, the required keys are 'uri',
+ * 'title' and 'link'. RSS also specifies three optional parameters 'width',
+ * 'height' and 'description'. Only 'uri' is required and used for Atom rendering.
+ *
+ * @param array $data
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setImage(array $data)
+ {
+ if (empty($data['uri']) || !is_string($data['uri'])
+ || !Uri::factory($data['uri'])->isValid()
+ ) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter \'uri\''
+ . ' must be a non-empty string and valid URI/IRI');
+ }
+ $this->data['image'] = $data;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed language
+ *
+ * @param string $language
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setLanguage($language)
+ {
+ if (empty($language) || !is_string($language)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['language'] = $language;
+
+ return $this;
+ }
+
+ /**
+ * Set a link to the HTML source
+ *
+ * @param string $link
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setLink($link)
+ {
+ if (empty($link) || !is_string($link) || !Uri::factory($link)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string and valid URI/IRI');
+ }
+ $this->data['link'] = $link;
+
+ return $this;
+ }
+
+ /**
+ * Set a link to an XML feed for any feed type/version
+ *
+ * @param string $link
+ * @param string $type
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setFeedLink($link, $type)
+ {
+ if (empty($link) || !is_string($link) || !Uri::factory($link)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "link"" must be a non-empty string and valid URI/IRI');
+ }
+ if (!in_array(strtolower($type), array('rss', 'rdf', 'atom'))) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "type"; You must declare the type of feed the link points to, i.e. RSS, RDF or Atom');
+ }
+ $this->data['feedLinks'][strtolower($type)] = $link;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed title
+ *
+ * @param string $title
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setTitle($title)
+ {
+ if (empty($title) || !is_string($title)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['title'] = $title;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed character encoding
+ *
+ * @param string $encoding
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setEncoding($encoding)
+ {
+ if (empty($encoding) || !is_string($encoding)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['encoding'] = $encoding;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed's base URL
+ *
+ * @param string $url
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function setBaseUrl($url)
+ {
+ if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "url" array value'
+ . ' must be a non-empty string and valid URI/IRI');
+ }
+ $this->data['baseUrl'] = $url;
+
+ return $this;
+ }
+
+ /**
+ * Add a Pubsubhubbub hub endpoint URL
+ *
+ * @param string $url
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function addHub($url)
+ {
+ if (empty($url) || !is_string($url) || !Uri::factory($url)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "url" array value'
+ . ' must be a non-empty string and valid URI/IRI');
+ }
+ if (!isset($this->data['hubs'])) {
+ $this->data['hubs'] = array();
+ }
+ $this->data['hubs'][] = $url;
+
+ return $this;
+ }
+
+ /**
+ * Add Pubsubhubbub hub endpoint URLs
+ *
+ * @param array $urls
+ * @return AbstractFeed
+ */
+ public function addHubs(array $urls)
+ {
+ foreach ($urls as $url) {
+ $this->addHub($url);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a feed category
+ *
+ * @param array $category
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractFeed
+ */
+ public function addCategory(array $category)
+ {
+ if (!isset($category['term'])) {
+ throw new Exception\InvalidArgumentException('Each category must be an array and '
+ . 'contain at least a "term" element containing the machine '
+ . ' readable category name');
+ }
+ if (isset($category['scheme'])) {
+ if (empty($category['scheme'])
+ || !is_string($category['scheme'])
+ || !Uri::factory($category['scheme'])->isValid()
+ ) {
+ throw new Exception\InvalidArgumentException('The Atom scheme or RSS domain of'
+ . ' a category must be a valid URI');
+ }
+ }
+ if (!isset($this->data['categories'])) {
+ $this->data['categories'] = array();
+ }
+ $this->data['categories'][] = $category;
+
+ return $this;
+ }
+
+ /**
+ * Set an array of feed categories
+ *
+ * @param array $categories
+ * @return AbstractFeed
+ */
+ public function addCategories(array $categories)
+ {
+ foreach ($categories as $category) {
+ $this->addCategory($category);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get a single author
+ *
+ * @param int $index
+ * @return string|null
+ */
+ public function getAuthor($index = 0)
+ {
+ if (isset($this->data['authors'][$index])) {
+ return $this->data['authors'][$index];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return array
+ */
+ public function getAuthors()
+ {
+ if (!array_key_exists('authors', $this->data)) {
+ return null;
+ }
+ return $this->data['authors'];
+ }
+
+ /**
+ * Get the copyright entry
+ *
+ * @return string|null
+ */
+ public function getCopyright()
+ {
+ if (!array_key_exists('copyright', $this->data)) {
+ return null;
+ }
+ return $this->data['copyright'];
+ }
+
+ /**
+ * Get the feed creation date
+ *
+ * @return string|null
+ */
+ public function getDateCreated()
+ {
+ if (!array_key_exists('dateCreated', $this->data)) {
+ return null;
+ }
+ return $this->data['dateCreated'];
+ }
+
+ /**
+ * Get the feed modification date
+ *
+ * @return string|null
+ */
+ public function getDateModified()
+ {
+ if (!array_key_exists('dateModified', $this->data)) {
+ return null;
+ }
+ return $this->data['dateModified'];
+ }
+
+ /**
+ * Get the feed last-build date
+ *
+ * @return string|null
+ */
+ public function getLastBuildDate()
+ {
+ if (!array_key_exists('lastBuildDate', $this->data)) {
+ return null;
+ }
+ return $this->data['lastBuildDate'];
+ }
+
+ /**
+ * Get the feed description
+ *
+ * @return string|null
+ */
+ public function getDescription()
+ {
+ if (!array_key_exists('description', $this->data)) {
+ return null;
+ }
+ return $this->data['description'];
+ }
+
+ /**
+ * Get the feed generator entry
+ *
+ * @return string|null
+ */
+ public function getGenerator()
+ {
+ if (!array_key_exists('generator', $this->data)) {
+ return null;
+ }
+ return $this->data['generator'];
+ }
+
+ /**
+ * Get the feed ID
+ *
+ * @return string|null
+ */
+ public function getId()
+ {
+ if (!array_key_exists('id', $this->data)) {
+ return null;
+ }
+ return $this->data['id'];
+ }
+
+ /**
+ * Get the feed image URI
+ *
+ * @return array
+ */
+ public function getImage()
+ {
+ if (!array_key_exists('image', $this->data)) {
+ return null;
+ }
+ return $this->data['image'];
+ }
+
+ /**
+ * Get the feed language
+ *
+ * @return string|null
+ */
+ public function getLanguage()
+ {
+ if (!array_key_exists('language', $this->data)) {
+ return null;
+ }
+ return $this->data['language'];
+ }
+
+ /**
+ * Get a link to the HTML source
+ *
+ * @return string|null
+ */
+ public function getLink()
+ {
+ if (!array_key_exists('link', $this->data)) {
+ return null;
+ }
+ return $this->data['link'];
+ }
+
+ /**
+ * Get a link to the XML feed
+ *
+ * @return string|null
+ */
+ public function getFeedLinks()
+ {
+ if (!array_key_exists('feedLinks', $this->data)) {
+ return null;
+ }
+ return $this->data['feedLinks'];
+ }
+
+ /**
+ * Get the feed title
+ *
+ * @return string|null
+ */
+ public function getTitle()
+ {
+ if (!array_key_exists('title', $this->data)) {
+ return null;
+ }
+ return $this->data['title'];
+ }
+
+ /**
+ * Get the feed character encoding
+ *
+ * @return string|null
+ */
+ public function getEncoding()
+ {
+ if (!array_key_exists('encoding', $this->data)) {
+ return 'UTF-8';
+ }
+ return $this->data['encoding'];
+ }
+
+ /**
+ * Get the feed's base url
+ *
+ * @return string|null
+ */
+ public function getBaseUrl()
+ {
+ if (!array_key_exists('baseUrl', $this->data)) {
+ return null;
+ }
+ return $this->data['baseUrl'];
+ }
+
+ /**
+ * Get the URLs used as Pubsubhubbub hubs endpoints
+ *
+ * @return string|null
+ */
+ public function getHubs()
+ {
+ if (!array_key_exists('hubs', $this->data)) {
+ return null;
+ }
+ return $this->data['hubs'];
+ }
+
+ /**
+ * Get the feed categories
+ *
+ * @return string|null
+ */
+ public function getCategories()
+ {
+ if (!array_key_exists('categories', $this->data)) {
+ return null;
+ }
+ return $this->data['categories'];
+ }
+
+ /**
+ * Resets the instance and deletes all data
+ *
+ * @return void
+ */
+ public function reset()
+ {
+ $this->data = array();
+ }
+
+ /**
+ * Set the current feed type being exported to "rss" or "atom". This allows
+ * other objects to gracefully choose whether to execute or not, depending
+ * on their appropriateness for the current type, e.g. renderers.
+ *
+ * @param string $type
+ * @return AbstractFeed
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * Retrieve the current or last feed type exported.
+ *
+ * @return string Value will be "rss" or "atom"
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Unset a specific data point
+ *
+ * @param string $name
+ * @return AbstractFeed
+ */
+ public function remove($name)
+ {
+ if (isset($this->data[$name])) {
+ unset($this->data[$name]);
+ }
+ return $this;
+ }
+
+ /**
+ * Method overloading: call given method on first extension implementing it
+ *
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ * @throws Exception\BadMethodCallException if no extensions implements the method
+ */
+ public function __call($method, $args)
+ {
+ foreach ($this->extensions as $extension) {
+ try {
+ return call_user_func_array(array($extension, $method), $args);
+ } catch (Exception\BadMethodCallException $e) {
+ }
+ }
+ throw new Exception\BadMethodCallException(
+ 'Method: ' . $method . ' does not exist and could not be located on a registered Extension'
+ );
+ }
+
+ /**
+ * Load extensions from Zend\Feed\Writer\Writer
+ *
+ * @throws Exception\RuntimeException
+ * @return void
+ */
+ protected function _loadExtensions()
+ {
+ $all = Writer::getExtensions();
+ $manager = Writer::getExtensionManager();
+ $exts = $all['feed'];
+ foreach ($exts as $ext) {
+ if (!$manager->has($ext)) {
+ throw new Exception\RuntimeException(sprintf('Unable to load extension "%s"; could not resolve to class', $ext));
+ }
+ $this->extensions[$ext] = $manager->get($ext);
+ $this->extensions[$ext]->setEncoding($this->getEncoding());
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Deleted.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Deleted.php
new file mode 100644
index 0000000..b9ff321
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Deleted.php
@@ -0,0 +1,237 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer;
+
+use DateTime;
+use Zend\Feed\Uri;
+
+/**
+*/
+class Deleted
+{
+
+ /**
+ * Internal array containing all data associated with this entry or item.
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * Holds the value "atom" or "rss" depending on the feed type set when
+ * when last exported.
+ *
+ * @var string
+ */
+ protected $type = null;
+
+ /**
+ * Set the feed character encoding
+ *
+ * @param $encoding
+ * @throws Exception\InvalidArgumentException
+ * @return string|null
+ * @return Deleted
+ */
+ public function setEncoding($encoding)
+ {
+ if (empty($encoding) || !is_string($encoding)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['encoding'] = $encoding;
+
+ return $this;
+ }
+
+ /**
+ * Get the feed character encoding
+ *
+ * @return string|null
+ */
+ public function getEncoding()
+ {
+ if (!array_key_exists('encoding', $this->data)) {
+ return 'UTF-8';
+ }
+ return $this->data['encoding'];
+ }
+
+ /**
+ * Unset a specific data point
+ *
+ * @param string $name
+ * @return Deleted
+ */
+ public function remove($name)
+ {
+ if (isset($this->data[$name])) {
+ unset($this->data[$name]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the current feed type being exported to "rss" or "atom". This allows
+ * other objects to gracefully choose whether to execute or not, depending
+ * on their appropriateness for the current type, e.g. renderers.
+ *
+ * @param string $type
+ * @return Deleted
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * Retrieve the current or last feed type exported.
+ *
+ * @return string Value will be "rss" or "atom"
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Set reference
+ *
+ * @param $reference
+ * @throws Exception\InvalidArgumentException
+ * @return Deleted
+ */
+ public function setReference($reference)
+ {
+ if (empty($reference) || !is_string($reference)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: reference must be a non-empty string');
+ }
+ $this->data['reference'] = $reference;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getReference()
+ {
+ if (!array_key_exists('reference', $this->data)) {
+ return null;
+ }
+ return $this->data['reference'];
+ }
+
+ /**
+ * Set when
+ *
+ * @param null|string|DateTime $date
+ * @throws Exception\InvalidArgumentException
+ * @return Deleted
+ */
+ public function setWhen($date = null)
+ {
+ if ($date === null) {
+ $date = new DateTime();
+ } elseif (is_int($date)) {
+ $date = new DateTime('@' . $date);
+ } elseif (!$date instanceof DateTime) {
+ throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp'
+ . ' passed as parameter');
+ }
+ $this->data['when'] = $date;
+
+ return $this;
+ }
+
+ /**
+ * @return DateTime
+ */
+ public function getWhen()
+ {
+ if (!array_key_exists('when', $this->data)) {
+ return null;
+ }
+ return $this->data['when'];
+ }
+
+ /**
+ * Set by
+ *
+ * @param array $by
+ * @throws Exception\InvalidArgumentException
+ * @return Deleted
+ */
+ public function setBy(array $by)
+ {
+ $author = array();
+ if (!array_key_exists('name', $by)
+ || empty($by['name'])
+ || !is_string($by['name'])
+ ) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: author array must include a'
+ . ' "name" key with a non-empty string value');
+ }
+ $author['name'] = $by['name'];
+ if (isset($by['email'])) {
+ if (empty($by['email']) || !is_string($by['email'])) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "email" array'
+ . ' value must be a non-empty string');
+ }
+ $author['email'] = $by['email'];
+ }
+ if (isset($by['uri'])) {
+ if (empty($by['uri'])
+ || !is_string($by['uri'])
+ || !Uri::factory($by['uri'])->isValid()
+ ) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "uri" array value must'
+ . ' be a non-empty string and valid URI/IRI');
+ }
+ $author['uri'] = $by['uri'];
+ }
+ $this->data['by'] = $author;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getBy()
+ {
+ if (!array_key_exists('by', $this->data)) {
+ return null;
+ }
+ return $this->data['by'];
+ }
+
+ /**
+ * @param string $comment
+ * @return Deleted
+ */
+ public function setComment($comment)
+ {
+ $this->data['comment'] = $comment;
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getComment()
+ {
+ if (!array_key_exists('comment', $this->data)) {
+ return null;
+ }
+ return $this->data['comment'];
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Entry.php
new file mode 100644
index 0000000..88a6fea
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Entry.php
@@ -0,0 +1,767 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer;
+
+use DateTime;
+use Zend\Feed\Uri;
+use Zend\Feed\Writer\Exception;
+
+/**
+*/
+class Entry
+{
+
+ /**
+ * Internal array containing all data associated with this entry or item.
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * Registered extensions
+ *
+ * @var array
+ */
+ protected $extensions = array();
+
+ /**
+ * Holds the value "atom" or "rss" depending on the feed type set when
+ * when last exported.
+ *
+ * @var string
+ */
+ protected $type = null;
+
+ /**
+ * Constructor: Primarily triggers the registration of core extensions and
+ * loads those appropriate to this data container.
+ *
+ */
+ public function __construct()
+ {
+ Writer::registerCoreExtensions();
+ $this->_loadExtensions();
+ }
+
+ /**
+ * Set a single author
+ *
+ * The following option keys are supported:
+ * 'name' => (string) The name
+ * 'email' => (string) An optional email
+ * 'uri' => (string) An optional and valid URI
+ *
+ * @param array $author
+ * @throws Exception\InvalidArgumentException If any value of $author not follow the format.
+ * @return Entry
+ */
+ public function addAuthor(array $author)
+ {
+ // Check array values
+ if (!array_key_exists('name', $author)
+ || empty($author['name'])
+ || !is_string($author['name'])
+ ) {
+ throw new Exception\InvalidArgumentException(
+ 'Invalid parameter: author array must include a "name" key with a non-empty string value');
+ }
+
+ if (isset($author['email'])) {
+ if (empty($author['email']) || !is_string($author['email'])) {
+ throw new Exception\InvalidArgumentException(
+ 'Invalid parameter: "email" array value must be a non-empty string');
+ }
+ }
+ if (isset($author['uri'])) {
+ if (empty($author['uri']) || !is_string($author['uri']) ||
+ !Uri::factory($author['uri'])->isValid()
+ ) {
+ throw new Exception\InvalidArgumentException(
+ 'Invalid parameter: "uri" array value must be a non-empty string and valid URI/IRI');
+ }
+ }
+
+ $this->data['authors'][] = $author;
+
+ return $this;
+ }
+
+ /**
+ * Set an array with feed authors
+ *
+ * @see addAuthor
+ * @param array $authors
+ * @return Entry
+ */
+ public function addAuthors(array $authors)
+ {
+ foreach ($authors as $author) {
+ $this->addAuthor($author);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the feed character encoding
+ *
+ * @param string $encoding
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setEncoding($encoding)
+ {
+ if (empty($encoding) || !is_string($encoding)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['encoding'] = $encoding;
+
+ return $this;
+ }
+
+ /**
+ * Get the feed character encoding
+ *
+ * @return string|null
+ */
+ public function getEncoding()
+ {
+ if (!array_key_exists('encoding', $this->data)) {
+ return 'UTF-8';
+ }
+ return $this->data['encoding'];
+ }
+
+ /**
+ * Set the copyright entry
+ *
+ * @param string $copyright
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setCopyright($copyright)
+ {
+ if (empty($copyright) || !is_string($copyright)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['copyright'] = $copyright;
+
+ return $this;
+ }
+
+ /**
+ * Set the entry's content
+ *
+ * @param string $content
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setContent($content)
+ {
+ if (empty($content) || !is_string($content)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['content'] = $content;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed creation date
+ *
+ * @param null|int|DateTime $date
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setDateCreated($date = null)
+ {
+ if ($date === null) {
+ $date = new DateTime();
+ } elseif (is_int($date)) {
+ $date = new DateTime('@' . $date);
+ } elseif (!$date instanceof DateTime) {
+ throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp passed as parameter');
+ }
+ $this->data['dateCreated'] = $date;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed modification date
+ *
+ * @param null|int|DateTime $date
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setDateModified($date = null)
+ {
+ if ($date === null) {
+ $date = new DateTime();
+ } elseif (is_int($date)) {
+ $date = new DateTime('@' . $date);
+ } elseif (!$date instanceof DateTime) {
+ throw new Exception\InvalidArgumentException('Invalid DateTime object or UNIX Timestamp passed as parameter');
+ }
+ $this->data['dateModified'] = $date;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed description
+ *
+ * @param string $description
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setDescription($description)
+ {
+ if (empty($description) || !is_string($description)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['description'] = $description;
+
+ return $this;
+ }
+
+ /**
+ * Set the feed ID
+ *
+ * @param string $id
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setId($id)
+ {
+ if (empty($id) || !is_string($id)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['id'] = $id;
+
+ return $this;
+ }
+
+ /**
+ * Set a link to the HTML source of this entry
+ *
+ * @param string $link
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setLink($link)
+ {
+ if (empty($link) || !is_string($link) || !Uri::factory($link)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string and valid URI/IRI');
+ }
+ $this->data['link'] = $link;
+
+ return $this;
+ }
+
+ /**
+ * Set the number of comments associated with this entry
+ *
+ * @param int $count
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setCommentCount($count)
+ {
+ if (!is_numeric($count) || (int) $count != $count || (int) $count < 0) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "count" must be a positive integer number or zero');
+ }
+ $this->data['commentCount'] = (int) $count;
+
+ return $this;
+ }
+
+ /**
+ * Set a link to a HTML page containing comments associated with this entry
+ *
+ * @param string $link
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setCommentLink($link)
+ {
+ if (empty($link) || !is_string($link) || !Uri::factory($link)->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "link" must be a non-empty string and valid URI/IRI');
+ }
+ $this->data['commentLink'] = $link;
+
+ return $this;
+ }
+
+ /**
+ * Set a link to an XML feed for any comments associated with this entry
+ *
+ * @param array $link
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setCommentFeedLink(array $link)
+ {
+ if (!isset($link['uri']) || !is_string($link['uri']) || !Uri::factory($link['uri'])->isValid()) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "link" must be a non-empty string and valid URI/IRI');
+ }
+ if (!isset($link['type']) || !in_array($link['type'], array('atom', 'rss', 'rdf'))) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: "type" must be one'
+ . ' of "atom", "rss" or "rdf"');
+ }
+ if (!isset($this->data['commentFeedLinks'])) {
+ $this->data['commentFeedLinks'] = array();
+ }
+ $this->data['commentFeedLinks'][] = $link;
+
+ return $this;
+ }
+
+ /**
+ * Set a links to an XML feed for any comments associated with this entry.
+ * Each link is an array with keys "uri" and "type", where type is one of:
+ * "atom", "rss" or "rdf".
+ *
+ * @param array $links
+ * @return Entry
+ */
+ public function setCommentFeedLinks(array $links)
+ {
+ foreach ($links as $link) {
+ $this->setCommentFeedLink($link);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the feed title
+ *
+ * @param string $title
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setTitle($title)
+ {
+ if (empty($title) || !is_string($title)) {
+ throw new Exception\InvalidArgumentException('Invalid parameter: parameter must be a non-empty string');
+ }
+ $this->data['title'] = $title;
+
+ return $this;
+ }
+
+ /**
+ * Get an array with feed authors
+ *
+ * @return array
+ */
+ public function getAuthors()
+ {
+ if (!array_key_exists('authors', $this->data)) {
+ return null;
+ }
+ return $this->data['authors'];
+ }
+
+ /**
+ * Get the entry content
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ if (!array_key_exists('content', $this->data)) {
+ return null;
+ }
+ return $this->data['content'];
+ }
+
+ /**
+ * Get the entry copyright information
+ *
+ * @return string
+ */
+ public function getCopyright()
+ {
+ if (!array_key_exists('copyright', $this->data)) {
+ return null;
+ }
+ return $this->data['copyright'];
+ }
+
+ /**
+ * Get the entry creation date
+ *
+ * @return string
+ */
+ public function getDateCreated()
+ {
+ if (!array_key_exists('dateCreated', $this->data)) {
+ return null;
+ }
+ return $this->data['dateCreated'];
+ }
+
+ /**
+ * Get the entry modification date
+ *
+ * @return string
+ */
+ public function getDateModified()
+ {
+ if (!array_key_exists('dateModified', $this->data)) {
+ return null;
+ }
+ return $this->data['dateModified'];
+ }
+
+ /**
+ * Get the entry description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ if (!array_key_exists('description', $this->data)) {
+ return null;
+ }
+ return $this->data['description'];
+ }
+
+ /**
+ * Get the entry ID
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ if (!array_key_exists('id', $this->data)) {
+ return null;
+ }
+ return $this->data['id'];
+ }
+
+ /**
+ * Get a link to the HTML source
+ *
+ * @return string|null
+ */
+ public function getLink()
+ {
+ if (!array_key_exists('link', $this->data)) {
+ return null;
+ }
+ return $this->data['link'];
+ }
+
+
+ /**
+ * Get all links
+ *
+ * @return array
+ */
+ public function getLinks()
+ {
+ if (!array_key_exists('links', $this->data)) {
+ return null;
+ }
+ return $this->data['links'];
+ }
+
+ /**
+ * Get the entry title
+ *
+ * @return string
+ */
+ public function getTitle()
+ {
+ if (!array_key_exists('title', $this->data)) {
+ return null;
+ }
+ return $this->data['title'];
+ }
+
+ /**
+ * Get the number of comments/replies for current entry
+ *
+ * @return int
+ */
+ public function getCommentCount()
+ {
+ if (!array_key_exists('commentCount', $this->data)) {
+ return null;
+ }
+ return $this->data['commentCount'];
+ }
+
+ /**
+ * Returns a URI pointing to the HTML page where comments can be made on this entry
+ *
+ * @return string
+ */
+ public function getCommentLink()
+ {
+ if (!array_key_exists('commentLink', $this->data)) {
+ return null;
+ }
+ return $this->data['commentLink'];
+ }
+
+ /**
+ * Returns an array of URIs pointing to a feed of all comments for this entry
+ * where the array keys indicate the feed type (atom, rss or rdf).
+ *
+ * @return string
+ */
+ public function getCommentFeedLinks()
+ {
+ if (!array_key_exists('commentFeedLinks', $this->data)) {
+ return null;
+ }
+ return $this->data['commentFeedLinks'];
+ }
+
+ /**
+ * Add a entry category
+ *
+ * @param array $category
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function addCategory(array $category)
+ {
+ if (!isset($category['term'])) {
+ throw new Exception\InvalidArgumentException('Each category must be an array and '
+ . 'contain at least a "term" element containing the machine '
+ . ' readable category name');
+ }
+ if (isset($category['scheme'])) {
+ if (empty($category['scheme'])
+ || !is_string($category['scheme'])
+ || !Uri::factory($category['scheme'])->isValid()
+ ) {
+ throw new Exception\InvalidArgumentException('The Atom scheme or RSS domain of'
+ . ' a category must be a valid URI');
+ }
+ }
+ if (!isset($this->data['categories'])) {
+ $this->data['categories'] = array();
+ }
+ $this->data['categories'][] = $category;
+
+ return $this;
+ }
+
+ /**
+ * Set an array of entry categories
+ *
+ * @param array $categories
+ * @return Entry
+ */
+ public function addCategories(array $categories)
+ {
+ foreach ($categories as $category) {
+ $this->addCategory($category);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the entry categories
+ *
+ * @return string|null
+ */
+ public function getCategories()
+ {
+ if (!array_key_exists('categories', $this->data)) {
+ return null;
+ }
+ return $this->data['categories'];
+ }
+
+ /**
+ * Adds an enclosure to the entry. The array parameter may contain the
+ * keys 'uri', 'type' and 'length'. Only 'uri' is required for Atom, though the
+ * others must also be provided or RSS rendering (where they are required)
+ * will throw an Exception.
+ *
+ * @param array $enclosure
+ * @throws Exception\InvalidArgumentException
+ * @return Entry
+ */
+ public function setEnclosure(array $enclosure)
+ {
+ if (!isset($enclosure['uri'])) {
+ throw new Exception\InvalidArgumentException('Enclosure "uri" is not set');
+ }
+ if (!Uri::factory($enclosure['uri'])->isValid()) {
+ throw new Exception\InvalidArgumentException('Enclosure "uri" is not a valid URI/IRI');
+ }
+ $this->data['enclosure'] = $enclosure;
+
+ return $this;
+ }
+
+ /**
+ * Retrieve an array of all enclosures to be added to entry.
+ *
+ * @return array
+ */
+ public function getEnclosure()
+ {
+ if (!array_key_exists('enclosure', $this->data)) {
+ return null;
+ }
+ return $this->data['enclosure'];
+ }
+
+ /**
+ * Unset a specific data point
+ *
+ * @param string $name
+ * @return Entry
+ */
+ public function remove($name)
+ {
+ if (isset($this->data[$name])) {
+ unset($this->data[$name]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get registered extensions
+ *
+ * @return array
+ */
+ public function getExtensions()
+ {
+ return $this->extensions;
+ }
+
+ /**
+ * Return an Extension object with the matching name (postfixed with _Entry)
+ *
+ * @param string $name
+ * @return object
+ */
+ public function getExtension($name)
+ {
+ if (array_key_exists($name . '\\Entry', $this->extensions)) {
+ return $this->extensions[$name . '\\Entry'];
+ }
+ return null;
+ }
+
+ /**
+ * Set the current feed type being exported to "rss" or "atom". This allows
+ * other objects to gracefully choose whether to execute or not, depending
+ * on their appropriateness for the current type, e.g. renderers.
+ *
+ * @param string $type
+ * @return Entry
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * Retrieve the current or last feed type exported.
+ *
+ * @return string Value will be "rss" or "atom"
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Method overloading: call given method on first extension implementing it
+ *
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ * @throws Exception\BadMethodCallException if no extensions implements the method
+ */
+ public function __call($method, $args)
+ {
+ foreach ($this->extensions as $extension) {
+ try {
+ return call_user_func_array(array($extension, $method), $args);
+ } catch (\BadMethodCallException $e) {
+ }
+ }
+ throw new Exception\BadMethodCallException('Method: ' . $method
+ . ' does not exist and could not be located on a registered Extension');
+ }
+
+ /**
+ * Creates a new Zend\Feed\Writer\Source data container for use. This is NOT
+ * added to the current feed automatically, but is necessary to create a
+ * container with some initial values preset based on the current feed data.
+ *
+ * @return Source
+ */
+ public function createSource()
+ {
+ $source = new Source;
+ if ($this->getEncoding()) {
+ $source->setEncoding($this->getEncoding());
+ }
+ $source->setType($this->getType());
+ return $source;
+ }
+
+ /**
+ * Appends a Zend\Feed\Writer\Entry object representing a new entry/item
+ * the feed data container's internal group of entries.
+ *
+ * @param Source $source
+ * @return Entry
+ */
+ public function setSource(Source $source)
+ {
+ $this->data['source'] = $source;
+ return $this;
+ }
+
+ /**
+ * @return Source
+ */
+ public function getSource()
+ {
+ if (isset($this->data['source'])) {
+ return $this->data['source'];
+ }
+ return null;
+ }
+
+ /**
+ * Load extensions from Zend\Feed\Writer\Writer
+ *
+ * @return void
+ */
+ protected function _loadExtensions()
+ {
+ $all = Writer::getExtensions();
+ $manager = Writer::getExtensionManager();
+ $exts = $all['entry'];
+ foreach ($exts as $ext) {
+ $this->extensions[$ext] = $manager->get($ext);
+ $this->extensions[$ext]->setEncoding($this->getEncoding());
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/BadMethodCallException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/BadMethodCallException.php
new file mode 100644
index 0000000..e969d21
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/BadMethodCallException.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Exception;
+
+use Zend\Feed\Exception;
+
+/**
+ * Feed exceptions
+ *
+ * Class to represent exceptions that occur during Feed operations.
+ */
+class BadMethodCallException
+ extends Exception\BadMethodCallException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/ExceptionInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/ExceptionInterface.php
new file mode 100644
index 0000000..dbcd279
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/ExceptionInterface.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Exception;
+
+/**
+ * Feed exceptions
+ *
+ * Interface to represent exceptions that occur during Feed operations.
+ */
+interface ExceptionInterface
+{
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/InvalidArgumentException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000..971eead
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/InvalidArgumentException.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Exception;
+
+use Zend\Feed\Exception;
+
+/**
+ * Feed exceptions
+ *
+ * Class to represent exceptions that occur during Feed operations.
+ */
+class InvalidArgumentException
+ extends Exception\InvalidArgumentException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/RuntimeException.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/RuntimeException.php
new file mode 100644
index 0000000..2c37bda
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Exception/RuntimeException.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Exception;
+
+use Zend\Feed\Exception;
+
+class RuntimeException
+ extends Exception\RuntimeException
+ implements ExceptionInterface
+{}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/AbstractRenderer.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/AbstractRenderer.php
new file mode 100644
index 0000000..7927e73
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/AbstractRenderer.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension;
+
+use DOMDocument;
+use DOMElement;
+
+/**
+*/
+abstract class AbstractRenderer implements RendererInterface
+{
+ /**
+ * @var DOMDocument
+ */
+ protected $dom = null;
+
+ /**
+ * @var mixed
+ */
+ protected $entry = null;
+
+ /**
+ * @var DOMElement
+ */
+ protected $base = null;
+
+ /**
+ * @var mixed
+ */
+ protected $container = null;
+
+ /**
+ * @var string
+ */
+ protected $type = null;
+
+ /**
+ * @var DOMElement
+ */
+ protected $rootElement = null;
+
+ /**
+ * Encoding of all text values
+ *
+ * @var string
+ */
+ protected $encoding = 'UTF-8';
+
+ /**
+ * Set the data container
+ *
+ * @param mixed $container
+ * @return AbstractRenderer
+ */
+ public function setDataContainer($container)
+ {
+ $this->container = $container;
+ return $this;
+ }
+
+ /**
+ * Set feed encoding
+ *
+ * @param string $enc
+ * @return AbstractRenderer
+ */
+ public function setEncoding($enc)
+ {
+ $this->encoding = $enc;
+ return $this;
+ }
+
+ /**
+ * Get feed encoding
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ return $this->encoding;
+ }
+
+ /**
+ * Set DOMDocument and DOMElement on which to operate
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $base
+ * @return AbstractRenderer
+ */
+ public function setDomDocument(DOMDocument $dom, DOMElement $base)
+ {
+ $this->dom = $dom;
+ $this->base = $base;
+ return $this;
+ }
+
+ /**
+ * Get data container being rendered
+ *
+ * @return mixed
+ */
+ public function getDataContainer()
+ {
+ return $this->container;
+ }
+
+ /**
+ * Set feed type
+ *
+ * @param string $type
+ * @return AbstractRenderer
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * Get feedtype
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Set root element of document
+ *
+ * @param DOMElement $root
+ * @return AbstractRenderer
+ */
+ public function setRootElement(DOMElement $root)
+ {
+ $this->rootElement = $root;
+ return $this;
+ }
+
+ /**
+ * Get root element
+ *
+ * @return DOMElement
+ */
+ public function getRootElement()
+ {
+ return $this->rootElement;
+ }
+
+ /**
+ * Append namespaces to feed
+ *
+ * @return void
+ */
+ abstract protected function _appendNamespaces();
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Atom/Renderer/Feed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Atom/Renderer/Feed.php
new file mode 100644
index 0000000..1d7023e
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Atom/Renderer/Feed.php
@@ -0,0 +1,109 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\Atom\Renderer;
+
+use DOMDocument;
+use DOMElement;
+use Zend\Feed\Writer\Extension;
+
+/**
+*/
+class Feed extends Extension\AbstractRenderer
+{
+
+ /**
+ * Set to TRUE if a rendering method actually renders something. This
+ * is used to prevent premature appending of a XML namespace declaration
+ * until an element which requires it is actually appended.
+ *
+ * @var bool
+ */
+ protected $called = false;
+
+ /**
+ * Render feed
+ *
+ * @return void
+ */
+ public function render()
+ {
+ /**
+ * RSS 2.0 only. Used mainly to include Atom links and
+ * Pubsubhubbub Hub endpoint URIs under the Atom namespace
+ */
+ if (strtolower($this->getType()) == 'atom') {
+ return;
+ }
+ $this->_setFeedLinks($this->dom, $this->base);
+ $this->_setHubs($this->dom, $this->base);
+ if ($this->called) {
+ $this->_appendNamespaces();
+ }
+ }
+
+ /**
+ * Append namespaces to root element of feed
+ *
+ * @return void
+ */
+ protected function _appendNamespaces()
+ {
+ $this->getRootElement()->setAttribute('xmlns:atom',
+ 'http://www.w3.org/2005/Atom');
+ }
+
+ /**
+ * Set feed link elements
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setFeedLinks(DOMDocument $dom, DOMElement $root)
+ {
+ $flinks = $this->getDataContainer()->getFeedLinks();
+ if (!$flinks || empty($flinks)) {
+ return;
+ }
+ foreach ($flinks as $type => $href) {
+ if (strtolower($type) == $this->getType()) { // issue 2605
+ $mime = 'application/' . strtolower($type) . '+xml';
+ $flink = $dom->createElement('atom:link');
+ $root->appendChild($flink);
+ $flink->setAttribute('rel', 'self');
+ $flink->setAttribute('type', $mime);
+ $flink->setAttribute('href', $href);
+ }
+ }
+ $this->called = true;
+ }
+
+ /**
+ * Set PuSH hubs
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setHubs(DOMDocument $dom, DOMElement $root)
+ {
+ $hubs = $this->getDataContainer()->getHubs();
+ if (!$hubs || empty($hubs)) {
+ return;
+ }
+ foreach ($hubs as $hubUrl) {
+ $hub = $dom->createElement('atom:link');
+ $hub->setAttribute('rel', 'hub');
+ $hub->setAttribute('href', $hubUrl);
+ $root->appendChild($hub);
+ }
+ $this->called = true;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Content/Renderer/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Content/Renderer/Entry.php
new file mode 100644
index 0000000..8785fb7
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Content/Renderer/Entry.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\Content\Renderer;
+
+use DOMDocument;
+use DOMElement;
+use Zend\Feed\Writer\Extension;
+
+/**
+*/
+class Entry extends Extension\AbstractRenderer
+{
+
+ /**
+ * Set to TRUE if a rendering method actually renders something. This
+ * is used to prevent premature appending of a XML namespace declaration
+ * until an element which requires it is actually appended.
+ *
+ * @var bool
+ */
+ protected $called = false;
+
+ /**
+ * Render entry
+ *
+ * @return void
+ */
+ public function render()
+ {
+ if (strtolower($this->getType()) == 'atom') {
+ return;
+ }
+ $this->_setContent($this->dom, $this->base);
+ if ($this->called) {
+ $this->_appendNamespaces();
+ }
+ }
+
+ /**
+ * Append namespaces to root element
+ *
+ * @return void
+ */
+ protected function _appendNamespaces()
+ {
+ $this->getRootElement()->setAttribute('xmlns:content',
+ 'http://purl.org/rss/1.0/modules/content/');
+ }
+
+ /**
+ * Set entry content
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setContent(DOMDocument $dom, DOMElement $root)
+ {
+ $content = $this->getDataContainer()->getContent();
+ if (!$content) {
+ return;
+ }
+ $element = $dom->createElement('content:encoded');
+ $root->appendChild($element);
+ $cdata = $dom->createCDATASection($content);
+ $element->appendChild($cdata);
+ $this->called = true;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/DublinCore/Renderer/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/DublinCore/Renderer/Entry.php
new file mode 100644
index 0000000..fffefd5
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/DublinCore/Renderer/Entry.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\DublinCore\Renderer;
+
+use DOMDocument;
+use DOMElement;
+use Zend\Feed\Writer\Extension;
+
+/**
+*/
+class Entry extends Extension\AbstractRenderer
+{
+
+ /**
+ * Set to TRUE if a rendering method actually renders something. This
+ * is used to prevent premature appending of a XML namespace declaration
+ * until an element which requires it is actually appended.
+ *
+ * @var bool
+ */
+ protected $called = false;
+
+ /**
+ * Render entry
+ *
+ * @return void
+ */
+ public function render()
+ {
+ if (strtolower($this->getType()) == 'atom') {
+ return;
+ }
+ $this->_setAuthors($this->dom, $this->base);
+ if ($this->called) {
+ $this->_appendNamespaces();
+ }
+ }
+
+ /**
+ * Append namespaces to entry
+ *
+ * @return void
+ */
+ protected function _appendNamespaces()
+ {
+ $this->getRootElement()->setAttribute('xmlns:dc',
+ 'http://purl.org/dc/elements/1.1/');
+ }
+
+ /**
+ * Set entry author elements
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setAuthors(DOMDocument $dom, DOMElement $root)
+ {
+ $authors = $this->getDataContainer()->getAuthors();
+ if (!$authors || empty($authors)) {
+ return;
+ }
+ foreach ($authors as $data) {
+ $author = $this->dom->createElement('dc:creator');
+ if (array_key_exists('name', $data)) {
+ $text = $dom->createTextNode($data['name']);
+ $author->appendChild($text);
+ $root->appendChild($author);
+ }
+ }
+ $this->called = true;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/DublinCore/Renderer/Feed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/DublinCore/Renderer/Feed.php
new file mode 100644
index 0000000..ceb3fac
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/DublinCore/Renderer/Feed.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\DublinCore\Renderer;
+
+use DOMDocument;
+use DOMElement;
+use Zend\Feed\Writer\Extension;
+
+/**
+*/
+class Feed extends Extension\AbstractRenderer
+{
+
+ /**
+ * Set to TRUE if a rendering method actually renders something. This
+ * is used to prevent premature appending of a XML namespace declaration
+ * until an element which requires it is actually appended.
+ *
+ * @var bool
+ */
+ protected $called = false;
+
+ /**
+ * Render feed
+ *
+ * @return void
+ */
+ public function render()
+ {
+ if (strtolower($this->getType()) == 'atom') {
+ return;
+ }
+ $this->_setAuthors($this->dom, $this->base);
+ if ($this->called) {
+ $this->_appendNamespaces();
+ }
+ }
+
+ /**
+ * Append namespaces to feed element
+ *
+ * @return void
+ */
+ protected function _appendNamespaces()
+ {
+ $this->getRootElement()->setAttribute('xmlns:dc',
+ 'http://purl.org/dc/elements/1.1/');
+ }
+
+ /**
+ * Set feed authors
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setAuthors(DOMDocument $dom, DOMElement $root)
+ {
+ $authors = $this->getDataContainer()->getAuthors();
+ if (!$authors || empty($authors)) {
+ return;
+ }
+ foreach ($authors as $data) {
+ $author = $this->dom->createElement('dc:creator');
+ if (array_key_exists('name', $data)) {
+ $text = $dom->createTextNode($data['name']);
+ $author->appendChild($text);
+ $root->appendChild($author);
+ }
+ }
+ $this->called = true;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Entry.php
new file mode 100644
index 0000000..f136293
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Entry.php
@@ -0,0 +1,246 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\ITunes;
+
+use Zend\Feed\Writer;
+use Zend\Feed\Writer\Extension;
+use Zend\Stdlib\StringUtils;
+use Zend\Stdlib\StringWrapper\StringWrapperInterface;
+
+/**
+*/
+class Entry
+{
+ /**
+ * Array of Feed data for rendering by Extension's renderers
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * Encoding of all text values
+ *
+ * @var string
+ */
+ protected $encoding = 'UTF-8';
+
+ /**
+ * The used string wrapper supporting encoding
+ *
+ * @var StringWrapperInterface
+ */
+ protected $stringWrapper;
+
+ public function __construct()
+ {
+ $this->stringWrapper = StringUtils::getWrapper($this->encoding);
+ }
+
+ /**
+ * Set feed encoding
+ *
+ * @param string $enc
+ * @return Entry
+ */
+ public function setEncoding($enc)
+ {
+ $this->stringWrapper = StringUtils::getWrapper($enc);
+ $this->encoding = $enc;
+ return $this;
+ }
+
+ /**
+ * Get feed encoding
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ return $this->encoding;
+ }
+
+ /**
+ * Set a block value of "yes" or "no". You may also set an empty string.
+ *
+ * @param string
+ * @return Entry
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesBlock($value)
+ {
+ if (!ctype_alpha($value) && strlen($value) > 0) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "block" may only'
+ . ' contain alphabetic characters');
+ }
+
+ if ($this->stringWrapper->strlen($value) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "block" may only'
+ . ' contain a maximum of 255 characters');
+ }
+ $this->data['block'] = $value;
+ }
+
+ /**
+ * Add authors to itunes entry
+ *
+ * @param array $values
+ * @return Entry
+ */
+ public function addItunesAuthors(array $values)
+ {
+ foreach ($values as $value) {
+ $this->addItunesAuthor($value);
+ }
+ return $this;
+ }
+
+ /**
+ * Add author to itunes entry
+ *
+ * @param string $value
+ * @return Entry
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function addItunesAuthor($value)
+ {
+ if ($this->stringWrapper->strlen($value) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "author" may only'
+ . ' contain a maximum of 255 characters each');
+ }
+ if (!isset($this->data['authors'])) {
+ $this->data['authors'] = array();
+ }
+ $this->data['authors'][] = $value;
+ return $this;
+ }
+
+ /**
+ * Set duration
+ *
+ * @param int $value
+ * @return Entry
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesDuration($value)
+ {
+ $value = (string) $value;
+ if (!ctype_digit($value)
+ && !preg_match("/^\d+:[0-5]{1}[0-9]{1}$/", $value)
+ && !preg_match("/^\d+:[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}$/", $value)
+ ) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "duration" may only'
+ . ' be of a specified [[HH:]MM:]SS format');
+ }
+ $this->data['duration'] = $value;
+ return $this;
+ }
+
+ /**
+ * Set "explicit" flag
+ *
+ * @param bool $value
+ * @return Entry
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesExplicit($value)
+ {
+ if (!in_array($value, array('yes', 'no', 'clean'))) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "explicit" may only'
+ . ' be one of "yes", "no" or "clean"');
+ }
+ $this->data['explicit'] = $value;
+ return $this;
+ }
+
+ /**
+ * Set keywords
+ *
+ * @param array $value
+ * @return Entry
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesKeywords(array $value)
+ {
+ if (count($value) > 12) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "keywords" may only'
+ . ' contain a maximum of 12 terms');
+ }
+
+ $concat = implode(',', $value);
+ if ($this->stringWrapper->strlen($concat) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "keywords" may only'
+ . ' have a concatenated length of 255 chars where terms are delimited'
+ . ' by a comma');
+ }
+ $this->data['keywords'] = $value;
+ return $this;
+ }
+
+ /**
+ * Set subtitle
+ *
+ * @param string $value
+ * @return Entry
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesSubtitle($value)
+ {
+ if ($this->stringWrapper->strlen($value) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "subtitle" may only'
+ . ' contain a maximum of 255 characters');
+ }
+ $this->data['subtitle'] = $value;
+ return $this;
+ }
+
+ /**
+ * Set summary
+ *
+ * @param string $value
+ * @return Entry
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesSummary($value)
+ {
+ if ($this->stringWrapper->strlen($value) > 4000) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "summary" may only'
+ . ' contain a maximum of 4000 characters');
+ }
+ $this->data['summary'] = $value;
+ return $this;
+ }
+
+ /**
+ * Overloading to itunes specific setters
+ *
+ * @param string $method
+ * @param array $params
+ * @throws Writer\Exception\BadMethodCallException
+ * @return mixed
+ */
+ public function __call($method, array $params)
+ {
+ $point = lcfirst(substr($method, 9));
+ if (!method_exists($this, 'setItunes' . ucfirst($point))
+ && !method_exists($this, 'addItunes' . ucfirst($point))
+ ) {
+ throw new Writer\Exception\BadMethodCallException(
+ 'invalid method: ' . $method
+ );
+ }
+ if (!array_key_exists($point, $this->data)
+ || empty($this->data[$point])
+ ) {
+ return null;
+ }
+ return $this->data[$point];
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Feed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Feed.php
new file mode 100644
index 0000000..7e6c5ac
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Feed.php
@@ -0,0 +1,362 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\ITunes;
+
+use Zend\Feed\Uri;
+use Zend\Feed\Writer;
+use Zend\Stdlib\StringUtils;
+use Zend\Stdlib\StringWrapper\StringWrapperInterface;
+
+/**
+*/
+class Feed
+{
+ /**
+ * Array of Feed data for rendering by Extension's renderers
+ *
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * Encoding of all text values
+ *
+ * @var string
+ */
+ protected $encoding = 'UTF-8';
+
+ /**
+ * The used string wrapper supporting encoding
+ *
+ * @var StringWrapperInterface
+ */
+ protected $stringWrapper;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->stringWrapper = StringUtils::getWrapper($this->encoding);
+ }
+
+ /**
+ * Set feed encoding
+ *
+ * @param string $enc
+ * @return Feed
+ */
+ public function setEncoding($enc)
+ {
+ $this->stringWrapper = StringUtils::getWrapper($enc);
+ $this->encoding = $enc;
+ return $this;
+ }
+
+ /**
+ * Get feed encoding
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ return $this->encoding;
+ }
+
+ /**
+ * Set a block value of "yes" or "no". You may also set an empty string.
+ *
+ * @param string
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesBlock($value)
+ {
+ if (!ctype_alpha($value) && strlen($value) > 0) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "block" may only'
+ . ' contain alphabetic characters');
+ }
+ if ($this->stringWrapper->strlen($value) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "block" may only'
+ . ' contain a maximum of 255 characters');
+ }
+ $this->data['block'] = $value;
+ return $this;
+ }
+
+ /**
+ * Add feed authors
+ *
+ * @param array $values
+ * @return Feed
+ */
+ public function addItunesAuthors(array $values)
+ {
+ foreach ($values as $value) {
+ $this->addItunesAuthor($value);
+ }
+ return $this;
+ }
+
+ /**
+ * Add feed author
+ *
+ * @param string $value
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function addItunesAuthor($value)
+ {
+ if ($this->stringWrapper->strlen($value) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "author" may only'
+ . ' contain a maximum of 255 characters each');
+ }
+ if (!isset($this->data['authors'])) {
+ $this->data['authors'] = array();
+ }
+ $this->data['authors'][] = $value;
+ return $this;
+ }
+
+ /**
+ * Set feed categories
+ *
+ * @param array $values
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesCategories(array $values)
+ {
+ if (!isset($this->data['categories'])) {
+ $this->data['categories'] = array();
+ }
+ foreach ($values as $key => $value) {
+ if (!is_array($value)) {
+ if ($this->stringWrapper->strlen($value) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "category" may only'
+ . ' contain a maximum of 255 characters each');
+ }
+ $this->data['categories'][] = $value;
+ } else {
+ if ($this->stringWrapper->strlen($key) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "category" may only'
+ . ' contain a maximum of 255 characters each');
+ }
+ $this->data['categories'][$key] = array();
+ foreach ($value as $val) {
+ if ($this->stringWrapper->strlen($val) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "category" may only'
+ . ' contain a maximum of 255 characters each');
+ }
+ $this->data['categories'][$key][] = $val;
+ }
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set feed image (icon)
+ *
+ * @param string $value
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesImage($value)
+ {
+ if (!Uri::factory($value)->isValid()) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "image" may only'
+ . ' be a valid URI/IRI');
+ }
+ if (!in_array(substr($value, -3), array('jpg', 'png'))) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "image" may only'
+ . ' use file extension "jpg" or "png" which must be the last three'
+ . ' characters of the URI (i.e. no query string or fragment)');
+ }
+ $this->data['image'] = $value;
+ return $this;
+ }
+
+ /**
+ * Set feed cumulative duration
+ *
+ * @param string $value
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesDuration($value)
+ {
+ $value = (string) $value;
+ if (!ctype_digit($value)
+ && !preg_match("/^\d+:[0-5]{1}[0-9]{1}$/", $value)
+ && !preg_match("/^\d+:[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}$/", $value)
+ ) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "duration" may only'
+ . ' be of a specified [[HH:]MM:]SS format');
+ }
+ $this->data['duration'] = $value;
+ return $this;
+ }
+
+ /**
+ * Set "explicit" flag
+ *
+ * @param bool $value
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesExplicit($value)
+ {
+ if (!in_array($value, array('yes', 'no', 'clean'))) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "explicit" may only'
+ . ' be one of "yes", "no" or "clean"');
+ }
+ $this->data['explicit'] = $value;
+ return $this;
+ }
+
+ /**
+ * Set feed keywords
+ *
+ * @param array $value
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesKeywords(array $value)
+ {
+ if (count($value) > 12) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "keywords" may only'
+ . ' contain a maximum of 12 terms');
+ }
+ $concat = implode(',', $value);
+ if ($this->stringWrapper->strlen($concat) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "keywords" may only'
+ . ' have a concatenated length of 255 chars where terms are delimited'
+ . ' by a comma');
+ }
+ $this->data['keywords'] = $value;
+ return $this;
+ }
+
+ /**
+ * Set new feed URL
+ *
+ * @param string $value
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesNewFeedUrl($value)
+ {
+ if (!Uri::factory($value)->isValid()) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "newFeedUrl" may only'
+ . ' be a valid URI/IRI');
+ }
+ $this->data['newFeedUrl'] = $value;
+ return $this;
+ }
+
+ /**
+ * Add feed owners
+ *
+ * @param array $values
+ * @return Feed
+ */
+ public function addItunesOwners(array $values)
+ {
+ foreach ($values as $value) {
+ $this->addItunesOwner($value);
+ }
+ return $this;
+ }
+
+ /**
+ * Add feed owner
+ *
+ * @param array $value
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function addItunesOwner(array $value)
+ {
+ if (!isset($value['name']) || !isset($value['email'])) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "owner" must'
+ . ' be an array containing keys "name" and "email"');
+ }
+ if ($this->stringWrapper->strlen($value['name']) > 255
+ || $this->stringWrapper->strlen($value['email']) > 255
+ ) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: any "owner" may only'
+ . ' contain a maximum of 255 characters each for "name" and "email"');
+ }
+ if (!isset($this->data['owners'])) {
+ $this->data['owners'] = array();
+ }
+ $this->data['owners'][] = $value;
+ return $this;
+ }
+
+ /**
+ * Set feed subtitle
+ *
+ * @param string $value
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesSubtitle($value)
+ {
+ if ($this->stringWrapper->strlen($value) > 255) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "subtitle" may only'
+ . ' contain a maximum of 255 characters');
+ }
+ $this->data['subtitle'] = $value;
+ return $this;
+ }
+
+ /**
+ * Set feed summary
+ *
+ * @param string $value
+ * @return Feed
+ * @throws Writer\Exception\InvalidArgumentException
+ */
+ public function setItunesSummary($value)
+ {
+ if ($this->stringWrapper->strlen($value) > 4000) {
+ throw new Writer\Exception\InvalidArgumentException('invalid parameter: "summary" may only'
+ . ' contain a maximum of 4000 characters');
+ }
+ $this->data['summary'] = $value;
+ return $this;
+ }
+
+ /**
+ * Overloading: proxy to internal setters
+ *
+ * @param string $method
+ * @param array $params
+ * @return mixed
+ * @throws Writer\Exception\BadMethodCallException
+ */
+ public function __call($method, array $params)
+ {
+ $point = lcfirst(substr($method, 9));
+ if (!method_exists($this, 'setItunes' . ucfirst($point))
+ && !method_exists($this, 'addItunes' . ucfirst($point))
+ ) {
+ throw new Writer\Exception\BadMethodCallException(
+ 'invalid method: ' . $method
+ );
+ }
+ if (!array_key_exists($point, $this->data) || empty($this->data[$point])) {
+ return null;
+ }
+ return $this->data[$point];
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Renderer/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Renderer/Entry.php
new file mode 100644
index 0000000..b46d10c
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Renderer/Entry.php
@@ -0,0 +1,200 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\ITunes\Renderer;
+
+use DOMDocument;
+use DOMElement;
+use Zend\Feed\Writer\Extension;
+
+/**
+*/
+class Entry extends Extension\AbstractRenderer
+{
+ /**
+ * Set to TRUE if a rendering method actually renders something. This
+ * is used to prevent premature appending of a XML namespace declaration
+ * until an element which requires it is actually appended.
+ *
+ * @var bool
+ */
+ protected $called = false;
+
+ /**
+ * Render entry
+ *
+ * @return void
+ */
+ public function render()
+ {
+ $this->_setAuthors($this->dom, $this->base);
+ $this->_setBlock($this->dom, $this->base);
+ $this->_setDuration($this->dom, $this->base);
+ $this->_setExplicit($this->dom, $this->base);
+ $this->_setKeywords($this->dom, $this->base);
+ $this->_setSubtitle($this->dom, $this->base);
+ $this->_setSummary($this->dom, $this->base);
+ if ($this->called) {
+ $this->_appendNamespaces();
+ }
+ }
+
+ /**
+ * Append namespaces to entry root
+ *
+ * @return void
+ */
+ protected function _appendNamespaces()
+ {
+ $this->getRootElement()->setAttribute('xmlns:itunes',
+ 'http://www.itunes.com/dtds/podcast-1.0.dtd');
+ }
+
+ /**
+ * Set entry authors
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setAuthors(DOMDocument $dom, DOMElement $root)
+ {
+ $authors = $this->getDataContainer()->getItunesAuthors();
+ if (!$authors || empty($authors)) {
+ return;
+ }
+ foreach ($authors as $author) {
+ $el = $dom->createElement('itunes:author');
+ $text = $dom->createTextNode($author);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+ }
+
+ /**
+ * Set itunes block
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setBlock(DOMDocument $dom, DOMElement $root)
+ {
+ $block = $this->getDataContainer()->getItunesBlock();
+ if ($block === null) {
+ return;
+ }
+ $el = $dom->createElement('itunes:block');
+ $text = $dom->createTextNode($block);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set entry duration
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setDuration(DOMDocument $dom, DOMElement $root)
+ {
+ $duration = $this->getDataContainer()->getItunesDuration();
+ if (!$duration) {
+ return;
+ }
+ $el = $dom->createElement('itunes:duration');
+ $text = $dom->createTextNode($duration);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set explicit flag
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setExplicit(DOMDocument $dom, DOMElement $root)
+ {
+ $explicit = $this->getDataContainer()->getItunesExplicit();
+ if ($explicit === null) {
+ return;
+ }
+ $el = $dom->createElement('itunes:explicit');
+ $text = $dom->createTextNode($explicit);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set entry keywords
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setKeywords(DOMDocument $dom, DOMElement $root)
+ {
+ $keywords = $this->getDataContainer()->getItunesKeywords();
+ if (!$keywords || empty($keywords)) {
+ return;
+ }
+ $el = $dom->createElement('itunes:keywords');
+ $text = $dom->createTextNode(implode(',', $keywords));
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set entry subtitle
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setSubtitle(DOMDocument $dom, DOMElement $root)
+ {
+ $subtitle = $this->getDataContainer()->getItunesSubtitle();
+ if (!$subtitle) {
+ return;
+ }
+ $el = $dom->createElement('itunes:subtitle');
+ $text = $dom->createTextNode($subtitle);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set entry summary
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setSummary(DOMDocument $dom, DOMElement $root)
+ {
+ $summary = $this->getDataContainer()->getItunesSummary();
+ if (!$summary) {
+ return;
+ }
+ $el = $dom->createElement('itunes:summary');
+ $text = $dom->createTextNode($summary);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Renderer/Feed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Renderer/Feed.php
new file mode 100644
index 0000000..9799681
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/ITunes/Renderer/Feed.php
@@ -0,0 +1,304 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\ITunes\Renderer;
+
+use DOMDocument;
+use DOMElement;
+use Zend\Feed\Writer\Extension;
+
+/**
+*/
+class Feed extends Extension\AbstractRenderer
+{
+
+ /**
+ * Set to TRUE if a rendering method actually renders something. This
+ * is used to prevent premature appending of a XML namespace declaration
+ * until an element which requires it is actually appended.
+ *
+ * @var bool
+ */
+ protected $called = false;
+
+ /**
+ * Render feed
+ *
+ * @return void
+ */
+ public function render()
+ {
+ $this->_setAuthors($this->dom, $this->base);
+ $this->_setBlock($this->dom, $this->base);
+ $this->_setCategories($this->dom, $this->base);
+ $this->_setImage($this->dom, $this->base);
+ $this->_setDuration($this->dom, $this->base);
+ $this->_setExplicit($this->dom, $this->base);
+ $this->_setKeywords($this->dom, $this->base);
+ $this->_setNewFeedUrl($this->dom, $this->base);
+ $this->_setOwners($this->dom, $this->base);
+ $this->_setSubtitle($this->dom, $this->base);
+ $this->_setSummary($this->dom, $this->base);
+ if ($this->called) {
+ $this->_appendNamespaces();
+ }
+ }
+
+ /**
+ * Append feed namespaces
+ *
+ * @return void
+ */
+ protected function _appendNamespaces()
+ {
+ $this->getRootElement()->setAttribute('xmlns:itunes',
+ 'http://www.itunes.com/dtds/podcast-1.0.dtd');
+ }
+
+ /**
+ * Set feed authors
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setAuthors(DOMDocument $dom, DOMElement $root)
+ {
+ $authors = $this->getDataContainer()->getItunesAuthors();
+ if (!$authors || empty($authors)) {
+ return;
+ }
+ foreach ($authors as $author) {
+ $el = $dom->createElement('itunes:author');
+ $text = $dom->createTextNode($author);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ }
+ $this->called = true;
+ }
+
+ /**
+ * Set feed itunes block
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setBlock(DOMDocument $dom, DOMElement $root)
+ {
+ $block = $this->getDataContainer()->getItunesBlock();
+ if ($block === null) {
+ return;
+ }
+ $el = $dom->createElement('itunes:block');
+ $text = $dom->createTextNode($block);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set feed categories
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setCategories(DOMDocument $dom, DOMElement $root)
+ {
+ $cats = $this->getDataContainer()->getItunesCategories();
+ if (!$cats || empty($cats)) {
+ return;
+ }
+ foreach ($cats as $key => $cat) {
+ if (!is_array($cat)) {
+ $el = $dom->createElement('itunes:category');
+ $el->setAttribute('text', $cat);
+ $root->appendChild($el);
+ } else {
+ $el = $dom->createElement('itunes:category');
+ $el->setAttribute('text', $key);
+ $root->appendChild($el);
+ foreach ($cat as $subcat) {
+ $el2 = $dom->createElement('itunes:category');
+ $el2->setAttribute('text', $subcat);
+ $el->appendChild($el2);
+ }
+ }
+ }
+ $this->called = true;
+ }
+
+ /**
+ * Set feed image (icon)
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setImage(DOMDocument $dom, DOMElement $root)
+ {
+ $image = $this->getDataContainer()->getItunesImage();
+ if (!$image) {
+ return;
+ }
+ $el = $dom->createElement('itunes:image');
+ $el->setAttribute('href', $image);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set feed cumulative duration
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setDuration(DOMDocument $dom, DOMElement $root)
+ {
+ $duration = $this->getDataContainer()->getItunesDuration();
+ if (!$duration) {
+ return;
+ }
+ $el = $dom->createElement('itunes:duration');
+ $text = $dom->createTextNode($duration);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set explicit flag
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setExplicit(DOMDocument $dom, DOMElement $root)
+ {
+ $explicit = $this->getDataContainer()->getItunesExplicit();
+ if ($explicit === null) {
+ return;
+ }
+ $el = $dom->createElement('itunes:explicit');
+ $text = $dom->createTextNode($explicit);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set feed keywords
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setKeywords(DOMDocument $dom, DOMElement $root)
+ {
+ $keywords = $this->getDataContainer()->getItunesKeywords();
+ if (!$keywords || empty($keywords)) {
+ return;
+ }
+ $el = $dom->createElement('itunes:keywords');
+ $text = $dom->createTextNode(implode(',', $keywords));
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set feed's new URL
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setNewFeedUrl(DOMDocument $dom, DOMElement $root)
+ {
+ $url = $this->getDataContainer()->getItunesNewFeedUrl();
+ if (!$url) {
+ return;
+ }
+ $el = $dom->createElement('itunes:new-feed-url');
+ $text = $dom->createTextNode($url);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set feed owners
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setOwners(DOMDocument $dom, DOMElement $root)
+ {
+ $owners = $this->getDataContainer()->getItunesOwners();
+ if (!$owners || empty($owners)) {
+ return;
+ }
+ foreach ($owners as $owner) {
+ $el = $dom->createElement('itunes:owner');
+ $name = $dom->createElement('itunes:name');
+ $text = $dom->createTextNode($owner['name']);
+ $name->appendChild($text);
+ $email = $dom->createElement('itunes:email');
+ $text = $dom->createTextNode($owner['email']);
+ $email->appendChild($text);
+ $root->appendChild($el);
+ $el->appendChild($name);
+ $el->appendChild($email);
+ }
+ $this->called = true;
+ }
+
+ /**
+ * Set feed subtitle
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setSubtitle(DOMDocument $dom, DOMElement $root)
+ {
+ $subtitle = $this->getDataContainer()->getItunesSubtitle();
+ if (!$subtitle) {
+ return;
+ }
+ $el = $dom->createElement('itunes:subtitle');
+ $text = $dom->createTextNode($subtitle);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+
+ /**
+ * Set feed summary
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setSummary(DOMDocument $dom, DOMElement $root)
+ {
+ $summary = $this->getDataContainer()->getItunesSummary();
+ if (!$summary) {
+ return;
+ }
+ $el = $dom->createElement('itunes:summary');
+ $text = $dom->createTextNode($summary);
+ $el->appendChild($text);
+ $root->appendChild($el);
+ $this->called = true;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/RendererInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/RendererInterface.php
new file mode 100644
index 0000000..032313d
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/RendererInterface.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension;
+
+use DOMDocument;
+use DOMElement;
+
+/**
+*/
+interface RendererInterface
+{
+ /**
+ * Set the data container
+ *
+ * @param mixed $container
+ * @return void
+ */
+ public function setDataContainer($container);
+
+ /**
+ * Retrieve container
+ *
+ * @return mixed
+ */
+ public function getDataContainer();
+
+ /**
+ * Set DOMDocument and DOMElement on which to operate
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $base
+ * @return void
+ */
+ public function setDomDocument(DOMDocument $dom, DOMElement $base);
+
+ /**
+ * Render
+ *
+ * @return void
+ */
+ public function render();
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Slash/Renderer/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Slash/Renderer/Entry.php
new file mode 100644
index 0000000..80adb51
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Slash/Renderer/Entry.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\Slash\Renderer;
+
+use DOMDocument;
+use DOMElement;
+use Zend\Feed\Writer\Extension;
+
+/**
+*/
+class Entry extends Extension\AbstractRenderer
+{
+
+ /**
+ * Set to TRUE if a rendering method actually renders something. This
+ * is used to prevent premature appending of a XML namespace declaration
+ * until an element which requires it is actually appended.
+ *
+ * @var bool
+ */
+ protected $called = false;
+
+ /**
+ * Render entry
+ *
+ * @return void
+ */
+ public function render()
+ {
+ if (strtolower($this->getType()) == 'atom') {
+ return; // RSS 2.0 only
+ }
+ $this->_setCommentCount($this->dom, $this->base);
+ if ($this->called) {
+ $this->_appendNamespaces();
+ }
+ }
+
+ /**
+ * Append entry namespaces
+ *
+ * @return void
+ */
+ protected function _appendNamespaces()
+ {
+ $this->getRootElement()->setAttribute('xmlns:slash',
+ 'http://purl.org/rss/1.0/modules/slash/');
+ }
+
+ /**
+ * Set entry comment count
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setCommentCount(DOMDocument $dom, DOMElement $root)
+ {
+ $count = $this->getDataContainer()->getCommentCount();
+ if (!$count) {
+ $count = 0;
+ }
+ $tcount = $this->dom->createElement('slash:comments');
+ $tcount->nodeValue = $count;
+ $root->appendChild($tcount);
+ $this->called = true;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Threading/Renderer/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Threading/Renderer/Entry.php
new file mode 100644
index 0000000..ee66b8f
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/Threading/Renderer/Entry.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\Threading\Renderer;
+
+use DOMDocument;
+use DOMElement;
+use Zend\Feed\Writer\Extension;
+
+/**
+*/
+class Entry extends Extension\AbstractRenderer
+{
+
+ /**
+ * Set to TRUE if a rendering method actually renders something. This
+ * is used to prevent premature appending of a XML namespace declaration
+ * until an element which requires it is actually appended.
+ *
+ * @var bool
+ */
+ protected $called = false;
+
+ /**
+ * Render entry
+ *
+ * @return void
+ */
+ public function render()
+ {
+ if (strtolower($this->getType()) == 'rss') {
+ return; // Atom 1.0 only
+ }
+ $this->_setCommentLink($this->dom, $this->base);
+ $this->_setCommentFeedLinks($this->dom, $this->base);
+ $this->_setCommentCount($this->dom, $this->base);
+ if ($this->called) {
+ $this->_appendNamespaces();
+ }
+ }
+
+ /**
+ * Append entry namespaces
+ *
+ * @return void
+ */
+ protected function _appendNamespaces()
+ {
+ $this->getRootElement()->setAttribute('xmlns:thr',
+ 'http://purl.org/syndication/thread/1.0');
+ }
+
+ /**
+ * Set comment link
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setCommentLink(DOMDocument $dom, DOMElement $root)
+ {
+ $link = $this->getDataContainer()->getCommentLink();
+ if (!$link) {
+ return;
+ }
+ $clink = $this->dom->createElement('link');
+ $clink->setAttribute('rel', 'replies');
+ $clink->setAttribute('type', 'text/html');
+ $clink->setAttribute('href', $link);
+ $count = $this->getDataContainer()->getCommentCount();
+ if ($count !== null) {
+ $clink->setAttribute('thr:count', $count);
+ }
+ $root->appendChild($clink);
+ $this->called = true;
+ }
+
+ /**
+ * Set comment feed links
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setCommentFeedLinks(DOMDocument $dom, DOMElement $root)
+ {
+ $links = $this->getDataContainer()->getCommentFeedLinks();
+ if (!$links || empty($links)) {
+ return;
+ }
+ foreach ($links as $link) {
+ $flink = $this->dom->createElement('link');
+ $flink->setAttribute('rel', 'replies');
+ $flink->setAttribute('type', 'application/' . $link['type'] . '+xml');
+ $flink->setAttribute('href', $link['uri']);
+ $count = $this->getDataContainer()->getCommentCount();
+ if ($count !== null) {
+ $flink->setAttribute('thr:count', $count);
+ }
+ $root->appendChild($flink);
+ $this->called = true;
+ }
+ }
+
+ /**
+ * Set entry comment count
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setCommentCount(DOMDocument $dom, DOMElement $root)
+ {
+ $count = $this->getDataContainer()->getCommentCount();
+ if ($count === null) {
+ return;
+ }
+ $tcount = $this->dom->createElement('thr:total');
+ $tcount->nodeValue = $count;
+ $root->appendChild($tcount);
+ $this->called = true;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/WellFormedWeb/Renderer/Entry.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/WellFormedWeb/Renderer/Entry.php
new file mode 100644
index 0000000..f5da0b0
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Extension/WellFormedWeb/Renderer/Entry.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Extension\WellFormedWeb\Renderer;
+
+use DOMDocument;
+use DOMElement;
+use Zend\Feed\Writer\Extension;
+
+/**
+*/
+class Entry extends Extension\AbstractRenderer
+{
+
+ /**
+ * Set to TRUE if a rendering method actually renders something. This
+ * is used to prevent premature appending of a XML namespace declaration
+ * until an element which requires it is actually appended.
+ *
+ * @var bool
+ */
+ protected $called = false;
+
+ /**
+ * Render entry
+ *
+ * @return void
+ */
+ public function render()
+ {
+ if (strtolower($this->getType()) == 'atom') {
+ return; // RSS 2.0 only
+ }
+ $this->_setCommentFeedLinks($this->dom, $this->base);
+ if ($this->called) {
+ $this->_appendNamespaces();
+ }
+ }
+
+ /**
+ * Append entry namespaces
+ *
+ * @return void
+ */
+ protected function _appendNamespaces()
+ {
+ $this->getRootElement()->setAttribute('xmlns:wfw',
+ 'http://wellformedweb.org/CommentAPI/');
+ }
+
+ /**
+ * Set entry comment feed links
+ *
+ * @param DOMDocument $dom
+ * @param DOMElement $root
+ * @return void
+ */
+ protected function _setCommentFeedLinks(DOMDocument $dom, DOMElement $root)
+ {
+ $links = $this->getDataContainer()->getCommentFeedLinks();
+ if (!$links || empty($links)) {
+ return;
+ }
+ foreach ($links as $link) {
+ if ($link['type'] == 'rss') {
+ $flink = $this->dom->createElement('wfw:commentRss');
+ $text = $dom->createTextNode($link['uri']);
+ $flink->appendChild($text);
+ $root->appendChild($flink);
+ }
+ }
+ $this->called = true;
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionManager.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionManager.php
new file mode 100644
index 0000000..0bb4ce0
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionManager.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer;
+
+/**
+ * Default implementation of ExtensionManagerInterface
+ *
+ * Decorator of ExtensionPluginManager.
+ */
+class ExtensionManager implements ExtensionManagerInterface
+{
+ protected $pluginManager;
+
+ /**
+ * Constructor
+ *
+ * Seeds the extension manager with a plugin manager; if none provided,
+ * creates an instance.
+ *
+ * @param null|ExtensionPluginManager $pluginManager
+ */
+ public function __construct(ExtensionPluginManager $pluginManager = null)
+ {
+ if (null === $pluginManager) {
+ $pluginManager = new ExtensionPluginManager();
+ }
+ $this->pluginManager = $pluginManager;
+ }
+
+ /**
+ * Method overloading
+ *
+ * Proxy to composed ExtensionPluginManager instance.
+ *
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ * @throws Exception\BadMethodCallException
+ */
+ public function __call($method, $args)
+ {
+ if (!method_exists($this->pluginManager, $method)) {
+ throw new Exception\BadMethodCallException(sprintf(
+ 'Method by name of %s does not exist in %s',
+ $method,
+ __CLASS__
+ ));
+ }
+ return call_user_func_array(array($this->pluginManager, $method), $args);
+ }
+
+ /**
+ * Get the named extension
+ *
+ * @param string $name
+ * @return Extension\AbstractEntry|Extension\AbstractFeed
+ */
+ public function get($name)
+ {
+ return $this->pluginManager->get($name);
+ }
+
+ /**
+ * Do we have the named extension?
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function has($name)
+ {
+ return $this->pluginManager->has($name);
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionManagerInterface.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionManagerInterface.php
new file mode 100644
index 0000000..358e187
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionManagerInterface.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer;
+
+interface ExtensionManagerInterface
+{
+ /**
+ * Do we have the extension?
+ *
+ * @param string $extension
+ * @return bool
+ */
+ public function has($extension);
+
+ /**
+ * Retrieve the extension
+ *
+ * @param string $extension
+ * @return mixed
+ */
+ public function get($extension);
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionPluginManager.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionPluginManager.php
new file mode 100644
index 0000000..575794e
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/ExtensionPluginManager.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer;
+
+use Zend\ServiceManager\AbstractPluginManager;
+
+/**
+ * Plugin manager implementation for feed writer extensions
+ *
+ * Validation checks that we have an Entry, Feed, or Extension\AbstractRenderer.
+ */
+class ExtensionPluginManager extends AbstractPluginManager
+{
+ /**
+ * Default set of extension classes
+ *
+ * @var array
+ */
+ protected $invokableClasses = array(
+ 'atomrendererfeed' => 'Zend\Feed\Writer\Extension\Atom\Renderer\Feed',
+ 'contentrendererentry' => 'Zend\Feed\Writer\Extension\Content\Renderer\Entry',
+ 'dublincorerendererentry' => 'Zend\Feed\Writer\Extension\DublinCore\Renderer\Entry',
+ 'dublincorerendererfeed' => 'Zend\Feed\Writer\Extension\DublinCore\Renderer\Feed',
+ 'itunesentry' => 'Zend\Feed\Writer\Extension\ITunes\Entry',
+ 'itunesfeed' => 'Zend\Feed\Writer\Extension\ITunes\Feed',
+ 'itunesrendererentry' => 'Zend\Feed\Writer\Extension\ITunes\Renderer\Entry',
+ 'itunesrendererfeed' => 'Zend\Feed\Writer\Extension\ITunes\Renderer\Feed',
+ 'slashrendererentry' => 'Zend\Feed\Writer\Extension\Slash\Renderer\Entry',
+ 'threadingrendererentry' => 'Zend\Feed\Writer\Extension\Threading\Renderer\Entry',
+ 'wellformedwebrendererentry' => 'Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry',
+ );
+
+ /**
+ * Do not share instances
+ *
+ * @var bool
+ */
+ protected $shareByDefault = false;
+
+ /**
+ * Validate the plugin
+ *
+ * Checks that the extension loaded is of a valid type.
+ *
+ * @param mixed $plugin
+ * @return void
+ * @throws Exception\InvalidArgumentException if invalid
+ */
+ public function validatePlugin($plugin)
+ {
+ if ($plugin instanceof Extension\AbstractRenderer) {
+ // we're okay
+ return;
+ }
+
+ if ('Feed' == substr(get_class($plugin), -4)) {
+ // we're okay
+ return;
+ }
+
+ if ('Entry' == substr(get_class($plugin), -5)) {
+ // we're okay
+ return;
+ }
+
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'Plugin of type %s is invalid; must implement %s\Extension\RendererInterface '
+ . 'or the classname must end in "Feed" or "Entry"',
+ (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
+ __NAMESPACE__
+ ));
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Feed.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Feed.php
new file mode 100644
index 0000000..0922082
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Feed.php
@@ -0,0 +1,241 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer;
+
+use Countable;
+use Iterator;
+use Zend\Feed\Writer\Renderer;
+
+/**
+*/
+class Feed extends AbstractFeed implements Iterator, Countable
+{
+
+ /**
+ * Contains all entry objects
+ *
+ * @var array
+ */
+ protected $entries = array();
+
+ /**
+ * A pointer for the iterator to keep track of the entries array
+ *
+ * @var int
+ */
+ protected $entriesKey = 0;
+
+ /**
+ * Creates a new Zend\Feed\Writer\Entry data container for use. This is NOT
+ * added to the current feed automatically, but is necessary to create a
+ * container with some initial values preset based on the current feed data.
+ *
+ * @return \Zend\Feed\Writer\Entry
+ */
+ public function createEntry()
+ {
+ $entry = new Entry;
+ if ($this->getEncoding()) {
+ $entry->setEncoding($this->getEncoding());
+ }
+ $entry->setType($this->getType());
+ return $entry;
+ }
+
+ /**
+ * Appends a Zend\Feed\Writer\Deleted object representing a new entry tombstone
+ * to the feed data container's internal group of entries.
+ *
+ * @param Deleted $deleted
+ * @return void
+ */
+ public function addTombstone(Deleted $deleted)
+ {
+ $this->entries[] = $deleted;
+ }
+
+ /**
+ * Creates a new Zend\Feed\Writer\Deleted data container for use. This is NOT
+ * added to the current feed automatically, but is necessary to create a
+ * container with some initial values preset based on the current feed data.
+ *
+ * @return Deleted
+ */
+ public function createTombstone()
+ {
+ $deleted = new Deleted;
+ if ($this->getEncoding()) {
+ $deleted->setEncoding($this->getEncoding());
+ }
+ $deleted->setType($this->getType());
+ return $deleted;
+ }
+
+ /**
+ * Appends a Zend\Feed\Writer\Entry object representing a new entry/item
+ * the feed data container's internal group of entries.
+ *
+ * @param Entry $entry
+ * @return Feed
+ */
+ public function addEntry(Entry $entry)
+ {
+ $this->entries[] = $entry;
+ return $this;
+ }
+
+ /**
+ * Removes a specific indexed entry from the internal queue. Entries must be
+ * added to a feed container in order to be indexed.
+ *
+ * @param int $index
+ * @throws Exception\InvalidArgumentException
+ * @return Feed
+ */
+ public function removeEntry($index)
+ {
+ if (!isset($this->entries[$index])) {
+ throw new Exception\InvalidArgumentException('Undefined index: ' . $index . '. Entry does not exist.');
+ }
+ unset($this->entries[$index]);
+
+ return $this;
+ }
+
+ /**
+ * Retrieve a specific indexed entry from the internal queue. Entries must be
+ * added to a feed container in order to be indexed.
+ *
+ * @param int $index
+ * @throws Exception\InvalidArgumentException
+ */
+ public function getEntry($index = 0)
+ {
+ if (isset($this->entries[$index])) {
+ return $this->entries[$index];
+ }
+ throw new Exception\InvalidArgumentException('Undefined index: ' . $index . '. Entry does not exist.');
+ }
+
+ /**
+ * Orders all indexed entries by date, thus offering date ordered readable
+ * content where a parser (or Homo Sapien) ignores the generic rule that
+ * XML element order is irrelevant and has no intrinsic meaning.
+ *
+ * Using this method will alter the original indexation.
+ *
+ * @return Feed
+ */
+ public function orderByDate()
+ {
+ /**
+ * Could do with some improvement for performance perhaps
+ */
+ $timestamp = time();
+ $entries = array();
+ foreach ($this->entries as $entry) {
+ if ($entry->getDateModified()) {
+ $timestamp = (int) $entry->getDateModified()->getTimestamp();
+ } elseif ($entry->getDateCreated()) {
+ $timestamp = (int) $entry->getDateCreated()->getTimestamp();
+ }
+ $entries[$timestamp] = $entry;
+ }
+ krsort($entries, SORT_NUMERIC);
+ $this->entries = array_values($entries);
+
+ return $this;
+ }
+
+ /**
+ * Get the number of feed entries.
+ * Required by the Iterator interface.
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->entries);
+ }
+
+ /**
+ * Return the current entry
+ *
+ * @return Entry
+ */
+ public function current()
+ {
+ return $this->entries[$this->key()];
+ }
+
+ /**
+ * Return the current feed key
+ *
+ * @return mixed
+ */
+ public function key()
+ {
+ return $this->entriesKey;
+ }
+
+ /**
+ * Move the feed pointer forward
+ *
+ * @return void
+ */
+ public function next()
+ {
+ ++$this->entriesKey;
+ }
+
+ /**
+ * Reset the pointer in the feed object
+ *
+ * @return void
+ */
+ public function rewind()
+ {
+ $this->entriesKey = 0;
+ }
+
+ /**
+ * Check to see if the iterator is still valid
+ *
+ * @return bool
+ */
+ public function valid()
+ {
+ return 0 <= $this->entriesKey && $this->entriesKey < $this->count();
+ }
+
+ /**
+ * Attempt to build and return the feed resulting from the data set
+ *
+ * @param string $type The feed type "rss" or "atom" to export as
+ * @param bool $ignoreExceptions
+ * @throws Exception\InvalidArgumentException
+ * @return string
+ */
+ public function export($type, $ignoreExceptions = false)
+ {
+ $this->setType(strtolower($type));
+ $type = ucfirst($this->getType());
+ if ($type !== 'Rss' && $type !== 'Atom') {
+ throw new Exception\InvalidArgumentException('Invalid feed type specified: ' . $type . '.'
+ . ' Should be one of "rss" or "atom".');
+ }
+ $renderClass = 'Zend\\Feed\\Writer\\Renderer\\Feed\\' . $type;
+ $renderer = new $renderClass($this);
+ if ($ignoreExceptions) {
+ $renderer->ignoreExceptions();
+ }
+ return $renderer->render()->saveXml();
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/FeedFactory.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/FeedFactory.php
new file mode 100644
index 0000000..9cf8fba
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/FeedFactory.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer;
+
+use Traversable;
+
+abstract class FeedFactory
+{
+ /**
+ * Create and return a Feed based on data provided.
+ *
+ * @param array|Traversable $data
+ * @throws Exception\InvalidArgumentException
+ * @return Feed
+ */
+ public static function factory($data)
+ {
+ if (!is_array($data) && !$data instanceof Traversable) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s expects an array or Traversable argument; received "%s"',
+ __METHOD__,
+ (is_object($data) ? get_class($data) : gettype($data))
+ ));
+ }
+
+ $feed = new Feed();
+
+ foreach ($data as $key => $value) {
+ // Setters
+ $key = static::convertKey($key);
+ $method = 'set' . $key;
+ if (method_exists($feed, $method)) {
+ switch ($method) {
+ case 'setfeedlink':
+ if (!is_array($value)) {
+ // Need an array
+ break;
+ }
+ if (!array_key_exists('link', $value) || !array_key_exists('type', $value)) {
+ // Need both keys to set this correctly
+ break;
+ }
+ $feed->setFeedLink($value['link'], $value['type']);
+ break;
+ default:
+ $feed->$method($value);
+ break;
+ }
+ continue;
+ }
+
+ // Entries
+ if ('entries' == $key) {
+ static::createEntries($value, $feed);
+ continue;
+ }
+ }
+
+ return $feed;
+ }
+
+ /**
+ * Normalize a key
+ *
+ * @param string $key
+ * @return string
+ */
+ protected static function convertKey($key)
+ {
+ $key = str_replace('_', '', strtolower($key));
+ return $key;
+ }
+
+ /**
+ * Create and attach entries to a feed
+ *
+ * @param array|Traversable $entries
+ * @param Feed $feed
+ * @throws Exception\InvalidArgumentException
+ * @return void
+ */
+ protected static function createEntries($entries, Feed $feed)
+ {
+ if (!is_array($entries) && !$entries instanceof Traversable) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s::factory expects the "entries" value to be an array or Traversable; received "%s"',
+ get_called_class(),
+ (is_object($entries) ? get_class($entries) : gettype($entries))
+ ));
+ }
+
+ foreach ($entries as $data) {
+ if (!is_array($data) && !$data instanceof Traversable && !$data instanceof Entry) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s expects an array, Traversable, or Zend\Feed\Writer\Entry argument; received "%s"',
+ __METHOD__,
+ (is_object($data) ? get_class($data) : gettype($data))
+ ));
+ }
+
+ // Use case 1: Entry item
+ if ($data instanceof Entry) {
+ $feed->addEntry($data);
+ continue;
+ }
+
+ // Use case 2: iterate item and populate entry
+ $entry = $feed->createEntry();
+ foreach ($data as $key => $value) {
+ $key = static::convertKey($key);
+ $method = 'set' . $key;
+ if (!method_exists($entry, $method)) {
+ continue;
+ }
+ $entry->$method($value);
+ }
+ $feed->addEntry($entry);
+ }
+ }
+}
diff --git a/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/AbstractRenderer.php b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/AbstractRenderer.php
new file mode 100644
index 0000000..f981f49
--- /dev/null
+++ b/core/vendor/zendframework/zend-feed/Zend/Feed/Writer/Renderer/AbstractRenderer.php
@@ -0,0 +1,233 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Feed\Writer\Renderer;
+
+use DOMDocument;
+use DOMElement;
+use Zend\Feed\Writer;
+
+/**
+*/
+class AbstractRenderer
+{
+ /**
+ * Extensions
+ * @var array
+ */
+ protected $extensions = array();
+
+ /**
+ * @var Writer\AbstractFeed
+ */
+ protected $container = null;
+
+ /**
+ * @var DOMDocument
+ */
+ protected $dom = null;
+
+ /**
+ * @var bool
+ */
+ protected $ignoreExceptions = false;
+
+ /**
+ * @var array
+ */
+ protected $exceptions = array();
+
+ /**
+ * Encoding of all text values
+ *
+ * @var string
+ */
+ protected $encoding = 'UTF-8';
+
+ /**
+ * Holds the value "atom" or "rss" depending on the feed type set when
+ * when last exported.
+ *
+ * @var string
+ */
+ protected $type = null;
+
+ /**
+ * @var DOMElement
+ */
+ protected $rootElement = null;