Server IP : 213.176.29.180 / Your IP : 3.144.252.243 Web Server : Apache System : Linux 213.176.29.180.hostiran.name 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Tue Sep 24 05:16:59 EDT 2024 x86_64 User : webtaragh ( 1001) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON Directory (0750) : /home/webtaragh/public_html/.well-known/../ |
[ Home ] | [ C0mmand ] | [ Upload File ] |
---|
phpcollection/src/PhpCollection/Set.php 0000644 00000030653 14736103327 0014222 0 ustar 00 <?php namespace PhpCollection; use PhpOption\None; use PhpOption\Some; /** * Implementation of a Set. * * Each set guarantees that equal elements are only contained once in the Set. * * This implementation constraints Sets to either consist of objects that implement ObjectBasics, or objects that have * an external ObjectBasicsHandler implementation, or simple scalars. These types cannot be mixed within the same Set. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class Set implements SetInterface { const ELEM_TYPE_SCALAR = 1; const ELEM_TYPE_OBJECT = 2; const ELEM_TYPE_OBJECT_WITH_HANDLER = 3; private $elementType; private $elements = array(); private $elementCount = 0; private $lookup = array(); public function __construct(array $elements = array()) { $this->addAll($elements); } public function first() { if (empty($this->elements)) { return None::create(); } return new Some(reset($this->elements)); } public function last() { if (empty($this->elements)) { return None::create(); } return new Some(end($this->elements)); } public function getIterator() { return new \ArrayIterator(array_values($this->elements)); } public function addSet(SetInterface $set) { $this->addAll($set->all()); } public function take($number) { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('$number must be greater than 0, but got %d.', $number)); } return $this->createNew(array_slice($this->elements, 0, $number)); } /** * Extracts element from the head while the passed callable returns true. * * @param callable $callable receives elements of this Set as first argument, and returns true/false. * * @return Set */ public function takeWhile($callable) { $newElements = array(); for ($i=0,$c=count($this->elements); $i<$c; $i++) { if (call_user_func($callable, $this->elements[$i]) !== true) { break; } $newElements[] = $this->elements[$i]; } return $this->createNew($newElements); } public function drop($number) { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); } return $this->createNew(array_slice($this->elements, $number)); } public function dropRight($number) { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); } return $this->createNew(array_slice($this->elements, 0, -1 * $number)); } public function dropWhile($callable) { for ($i=0,$c=count($this->elements); $i<$c; $i++) { if (true !== call_user_func($callable, $this->elements[$i])) { break; } } return $this->createNew(array_slice($this->elements, $i)); } public function map($callable) { $newElements = array(); foreach ($this->elements as $i => $element) { $newElements[$i] = $callable($element); } return $this->createNew($newElements); } public function reverse() { return $this->createNew(array_reverse($this->elements)); } public function all() { return array_values($this->elements); } public function filterNot($callable) { return $this->filterInternal($callable, false); } public function filter($callable) { return $this->filterInternal($callable, true); } public function foldLeft($initialValue, $callable) { $value = $initialValue; foreach ($this->elements as $elem) { $value = call_user_func($callable, $value, $elem); } return $value; } public function foldRight($initialValue, $callable) { $value = $initialValue; foreach (array_reverse($this->elements) as $elem) { $value = call_user_func($callable, $elem, $value); } return $value; } public function addAll(array $elements) { foreach ($elements as $elem) { $this->add($elem); } } public function count() { return count($this->elements); } public function contains($elem) { if ($this->elementType === self::ELEM_TYPE_OBJECT) { if ($elem instanceof ObjectBasics) { return $this->containsObject($elem); } return false; } elseif ($this->elementType === self::ELEM_TYPE_OBJECT_WITH_HANDLER) { if (is_object($elem)) { return $this->containsObjectWithHandler($elem, ObjectBasicsHandlerRegistry::getHandler(get_class($elem))); } return false; } elseif ($this->elementType === self::ELEM_TYPE_SCALAR) { if (is_scalar($elem)) { return $this->containsScalar($elem); } return false; } return false; } public function remove($elem) { if ($this->elementType === self::ELEM_TYPE_OBJECT) { if ($elem instanceof ObjectBasics) { $this->removeObject($elem); } } elseif ($this->elementType === self::ELEM_TYPE_OBJECT_WITH_HANDLER) { if (is_object($elem)) { $this->removeObjectWithHandler($elem, ObjectBasicsHandlerRegistry::getHandler(get_class($elem))); } } elseif ($this->elementType === self::ELEM_TYPE_SCALAR) { if (is_scalar($elem)) { $this->removeScalar($elem); } } } public function isEmpty() { return empty($this->elements); } public function add($elem) { if ($this->elementType === null) { if ($elem instanceof ObjectBasics) { $this->addObject($elem); } elseif (is_scalar($elem)) { $this->addScalar($elem); } else { if (is_object($elem)) { $this->addObjectWithHandler($elem, ObjectBasicsHandlerRegistry::getHandler(get_class($elem))); } else { throw new \LogicException(sprintf('The type of $elem ("%s") is not supported in sets.', gettype($elem))); } } } elseif ($this->elementType === self::ELEM_TYPE_OBJECT) { if ($elem instanceof ObjectBasics) { $this->addObject($elem); return; } if (is_object($elem)) { throw new \LogicException(sprintf('This Set already contains object implement ObjectBasics, and cannot be mixed with objects that do not implement this interface like "%s".', get_class($elem))); } throw new \LogicException(sprintf('This Set already contains objects, and cannot be mixed with elements of type "%s".', gettype($elem))); } elseif ($this->elementType === self::ELEM_TYPE_OBJECT_WITH_HANDLER) { if (is_object($elem)) { $this->addObjectWithHandler($elem, ObjectBasicsHandlerRegistry::getHandler(get_class($elem))); return; } throw new \LogicException(sprintf('This Set already contains object with an external handler, and cannot be mixed with elements of type "%s".', gettype($elem))); } elseif ($this->elementType === self::ELEM_TYPE_SCALAR) { if (is_scalar($elem)) { $this->addScalar($elem); return; } throw new \LogicException(sprintf('This Set already contains scalars, and cannot be mixed with elements of type "%s".', gettype($elem))); } else { throw new \LogicException('Unknown element type in Set - should never be reached.'); } } protected function createNew(array $elements) { return new static($elements); } private function filterInternal($callable, $booleanKeep) { $newElements = array(); foreach ($this->elements as $element) { if ($booleanKeep !== call_user_func($callable, $element)) { continue; } $newElements[] = $element; } return $this->createNew($newElements); } private function containsScalar($elem) { if ( ! isset($this->lookup[$elem])) { return false; } foreach ($this->lookup[$elem] as $index) { if ($elem === $this->elements[$index]) { return true; } } return false; } private function containsObjectWithHandler($object, ObjectBasicsHandler $handler) { $hash = $handler->hash($object); if ( ! isset($this->lookup[$hash])) { return false; } foreach ($this->lookup[$hash] as $index) { if ($handler->equals($object, $this->elements[$index])) { return true; } } return false; } private function containsObject(ObjectBasics $object) { $hash = $object->hash(); if ( ! isset($this->lookup[$hash])) { return false; } foreach ($this->lookup[$hash] as $index) { if ($object->equals($this->elements[$index])) { return true; } } return false; } private function removeScalar($elem) { if ( ! isset($this->lookup[$elem])) { return; } foreach ($this->lookup[$elem] as $k => $index) { if ($elem === $this->elements[$index]) { $this->removeElement($elem, $k, $index); break; } } } private function removeObjectWithHandler($object, ObjectBasicsHandler $handler) { $hash = $handler->hash($object); if ( ! isset($this->lookup[$hash])) { return; } foreach ($this->lookup[$hash] as $k => $index) { if ($handler->equals($object, $this->elements[$index])) { $this->removeElement($hash, $k, $index); break; } } } private function removeObject(ObjectBasics $object) { $hash = $object->hash(); if ( ! isset($this->lookup[$hash])) { return; } foreach ($this->lookup[$hash] as $k => $index) { if ($object->equals($this->elements[$index])) { $this->removeElement($hash, $k, $index); break; } } } private function removeElement($hash, $lookupIndex, $storageIndex) { unset($this->lookup[$hash][$lookupIndex]); if (empty($this->lookup[$hash])) { unset($this->lookup[$hash]); } unset($this->elements[$storageIndex]); } private function addScalar($elem) { if (isset($this->lookup[$elem])) { foreach ($this->lookup[$elem] as $index) { if ($this->elements[$index] === $elem) { return; // Already exists. } } } $this->insertElement($elem, $elem); $this->elementType = self::ELEM_TYPE_SCALAR; } private function addObjectWithHandler($object, ObjectBasicsHandler $handler) { $hash = $handler->hash($object); if (isset($this->lookup[$hash])) { foreach ($this->lookup[$hash] as $index) { if ($handler->equals($object, $this->elements[$index])) { return; // Already exists. } } } $this->insertElement($object, $hash); $this->elementType = self::ELEM_TYPE_OBJECT_WITH_HANDLER; } private function addObject(ObjectBasics $elem) { $hash = $elem->hash(); if (isset($this->lookup[$hash])) { foreach ($this->lookup[$hash] as $index) { if ($elem->equals($this->elements[$index])) { return; // Element already exists. } } } $this->insertElement($elem, $hash); $this->elementType = self::ELEM_TYPE_OBJECT; } private function insertElement($elem, $hash) { $index = $this->elementCount++; $this->elements[$index] = $elem; $this->lookup[$hash][] = $index; } } phpcollection/src/PhpCollection/Map.php 0000644 00000001462 14736103327 0014200 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpCollection; class Map extends AbstractMap implements SortableInterface { public function sortWith($callable) { uksort($this->elements, $callable); } } phpcollection/src/PhpCollection/Sequence.php 0000644 00000002136 14736103327 0015232 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpCollection; /** * Unsorted sequence implementation. * * Characteristics: * * - Keys: consequentially numbered, without gaps * - Values: anything, duplicates allowed * - Ordering: same as input unless when explicitly sorted * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class Sequence extends AbstractSequence implements SortableInterface { public function sortWith($callable) { usort($this->elements, $callable); } } phpcollection/src/PhpCollection/MapInterface.php 0000644 00000010222 14736103327 0016013 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpCollection; use PhpOption\Option; /** * Basic map interface. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface MapInterface extends CollectionInterface { /** * Returns the first element in the collection if available. * * @return Option on array<K,V> */ public function first(); /** * Returns the last element in the collection if available. * * @return Option on array<K,V> */ public function last(); /** * Returns all elements in this collection. * * @return array */ public function all(); /** * Searches the collection for an element. * * @param callable $callable receives the element as first argument, and returns true, or false * * @return Option on array<K,V> */ public function find($callable); /** * Returns the value associated with the given key. * * @param mixed $key * * @return Option on V */ public function get($key); /** * Returns whether this map contains a given key. * * @param mixed $key * * @return boolean */ public function containsKey($key); /** * Puts a new element in the map. * * @param mixed $key * @param mixed $value * * @return void */ public function set($key, $value); /** * Removes an element from the map. * * @param mixed $key * * @return mixed */ public function remove($key); /** * Adds all another map to this map, and returns itself. * * @param MapInterface $map * * @return MapInterface */ public function addMap(MapInterface $map); /** * Returns an array with the keys. * * @return array */ public function keys(); /** * Returns an array with the values. * * @return array */ public function values(); /** * Returns a new sequence by omitting the given number of elements from the beginning. * * If the passed number is greater than the available number of elements, all will be removed. * * @param integer $number * * @return MapInterface */ public function drop($number); /** * Returns a new sequence by omitting the given number of elements from the end. * * If the passed number is greater than the available number of elements, all will be removed. * * @param integer $number * * @return MapInterface */ public function dropRight($number); /** * Returns a new sequence by omitting elements from the beginning for as long as the callable returns true. * * @param callable $callable Receives the element to drop as first argument, and returns true (drop), or false (stop). * * @return MapInterface */ public function dropWhile($callable); /** * Creates a new collection by taking the given number of elements from the beginning * of the current collection. * * If the passed number is greater than the available number of elements, then all elements * will be returned as a new collection. * * @param integer $number * * @return MapInterface */ public function take($number); /** * Creates a new collection by taking elements from the current collection * for as long as the callable returns true. * * @param callable $callable * * @return MapInterface */ public function takeWhile($callable); } phpcollection/src/PhpCollection/SetInterface.php 0000644 00000006173 14736103327 0016043 0 ustar 00 <?php namespace PhpCollection; use PhpOption\Option; /** * Interface for sets. * * Each Set contains equal values only once. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface SetInterface extends CollectionInterface, \IteratorAggregate { /** * @param object|scalar $elem * @return void */ public function add($elem); /** * @param object|scalar $elements * @return void */ public function addAll(array $elements); /** * @param object|scalar $elem * @return void */ public function remove($elem); /** * Returns the first element in the collection if available. * * @return Option */ public function first(); /** * Returns the last element in the collection if available. * * @return Option */ public function last(); /** * Returns all elements in this Set. * * @return array */ public function all(); /** * Returns a new Set with all elements in reverse order. * * @return SetInterface */ public function reverse(); /** * Adds the elements of another Set to this Set. * * @param SetInterface $seq * * @return SetInterface */ public function addSet(SetInterface $seq); /** * Returns a new Set by omitting the given number of elements from the beginning. * * If the passed number is greater than the available number of elements, all will be removed. * * @param integer $number * * @return SetInterface */ public function drop($number); /** * Returns a new Set by omitting the given number of elements from the end. * * If the passed number is greater than the available number of elements, all will be removed. * * @param integer $number * * @return SetInterface */ public function dropRight($number); /** * Returns a new Set by omitting elements from the beginning for as long as the callable returns true. * * @param callable $callable Receives the element to drop as first argument, and returns true (drop), or false (stop). * * @return SetInterface */ public function dropWhile($callable); /** * Creates a new collection by taking the given number of elements from the beginning * of the current collection. * * If the passed number is greater than the available number of elements, then all elements * will be returned as a new collection. * * @param integer $number * * @return CollectionInterface */ public function take($number); /** * Creates a new collection by taking elements from the current collection * for as long as the callable returns true. * * @param callable $callable * * @return CollectionInterface */ public function takeWhile($callable); /** * Creates a new collection by applying the passed callable to all elements * of the current collection. * * @param callable $callable * @return CollectionInterface */ public function map($callable); } phpcollection/src/PhpCollection/ObjectBasics.php 0000644 00000002406 14736103327 0016015 0 ustar 00 <?php namespace PhpCollection; /** * Interface that must be implemented by objects that are used as keys, or in sets. * * For entities, you can use the "EntityLikeObject" trait. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface ObjectBasics { /** * Produces a hash for the given object. * * If two objects are equal (as per the equals() method), the hash() method must produce * the same hash for them. * * The reverse can, but does not necessarily have to be true. That is, if two objects have the * same hash, they do not necessarily have to be equal, but the equals() method must be called * to be sure. * * When implementing this method try to use a simple and fast algorithm that produces reasonably * different results for non-equal objects, and shift the heavy comparison logic to equals(). * * @return string|integer */ public function hash(); /** * Whether two objects are equal. * * This can compare by referential equality (===), or in case of value objects like (\DateTime) compare * the individual properties of the objects; it's up to the implementation. * * @return boolean */ public function equals(ObjectBasics $other); } phpcollection/src/PhpCollection/AbstractSequence.php 0000644 00000021576 14736103327 0016727 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpCollection; use PhpOption\Some; use PhpOption\None; use PhpOption\Option; use OutOfBoundsException; /** * A sequence with numerically indexed elements. * * This is rawly equivalent to an array with only numeric keys. * There are no restrictions on how many same values may occur in the sequence. * * This sequence is mutable. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class AbstractSequence extends AbstractCollection implements \IteratorAggregate, SequenceInterface { protected $elements; /** * @param array $elements */ public function __construct(array $elements = array()) { $this->elements = array_values($elements); } public function addSequence(SequenceInterface $seq) { $this->addAll($seq->all()); } public function indexOf($searchedElement) { foreach ($this->elements as $i => $element) { if ($searchedElement === $element) { return $i; } } return -1; } public function lastIndexOf($searchedElement) { for ($i=count($this->elements)-1; $i>=0; $i--) { if ($this->elements[$i] === $searchedElement) { return $i; } } return -1; } public function reverse() { return $this->createNew(array_reverse($this->elements)); } public function isDefinedAt($index) { return isset($this->elements[$index]); } /** * Returns a filtered sequence. * * @param callable $callable receives the element and must return true (= keep) or false (= remove). * * @return AbstractSequence */ public function filter($callable) { return $this->filterInternal($callable, true); } public function map($callable) { $newElements = array(); foreach ($this->elements as $i => $element) { $newElements[$i] = $callable($element); } return $this->createNew($newElements); } /** * Returns a filtered sequence. * * @param callable $callable receives the element and must return true (= remove) or false (= keep). * * @return AbstractSequence */ public function filterNot($callable) { return $this->filterInternal($callable, false); } private function filterInternal($callable, $booleanKeep) { $newElements = array(); foreach ($this->elements as $element) { if ($booleanKeep !== call_user_func($callable, $element)) { continue; } $newElements[] = $element; } return $this->createNew($newElements); } public function foldLeft($initialValue, $callable) { $value = $initialValue; foreach ($this->elements as $elem) { $value = call_user_func($callable, $value, $elem); } return $value; } public function foldRight($initialValue, $callable) { $value = $initialValue; foreach (array_reverse($this->elements) as $elem) { $value = call_user_func($callable, $elem, $value); } return $value; } /** * Finds the first index where the given callable returns true. * * @param callable $callable * * @return integer the index, or -1 if the predicate is not true for any element. */ public function indexWhere($callable) { foreach ($this->elements as $i => $element) { if (call_user_func($callable, $element) === true) { return $i; } } return -1; } public function lastIndexWhere($callable) { for ($i=count($this->elements)-1; $i>=0; $i--) { if (call_user_func($callable, $this->elements[$i]) === true) { return $i; } } return -1; } public function last() { if (empty($this->elements)) { return None::create(); } return new Some(end($this->elements)); } public function first() { if (empty($this->elements)) { return None::create(); } return new Some(reset($this->elements)); } public function indices() { return array_keys($this->elements); } /** * Returns an element based on its index (0-based). * * @param integer $index * * @return T */ public function get($index) { if ( ! isset($this->elements[$index])) { throw new OutOfBoundsException(sprintf('The index "%s" does not exist in this sequence.', $index)); } return $this->elements[$index]; } /** * Removes the element at the given index, and returns it. * * @param int $index * * @return T * * @throws \OutOfBoundsException If there is no element at the given index. */ public function remove($index) { if ( ! isset($this->elements[$index])) { throw new OutOfBoundsException(sprintf('The index "%d" is not in the interval [0, %d).', $index, count($this->elements))); } $element = $this->elements[$index]; unset($this->elements[$index]); $this->elements = array_values($this->elements); return $element; } /** * Updates the element at the given index (0-based). * * @param integer $index * @param T $value */ public function update($index, $value) { if ( ! isset($this->elements[$index])) { throw new \InvalidArgumentException(sprintf('There is no element at index "%d".', $index)); } $this->elements[$index] = $value; } public function isEmpty() { return empty($this->elements); } public function all() { return $this->elements; } public function add($newElement) { $this->elements[] = $newElement; } public function addAll(array $addedElements) { foreach ($addedElements as $newElement) { $this->elements[] = $newElement; } } public function take($number) { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('$number must be greater than 0, but got %d.', $number)); } return $this->createNew(array_slice($this->elements, 0, $number)); } /** * Extracts element from the head while the passed callable returns true. * * @param callable $callable receives elements of this sequence as first argument, and returns true/false. * * @return Sequence */ public function takeWhile($callable) { $newElements = array(); for ($i=0,$c=count($this->elements); $i<$c; $i++) { if (call_user_func($callable, $this->elements[$i]) !== true) { break; } $newElements[] = $this->elements[$i]; } return $this->createNew($newElements); } public function drop($number) { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); } return $this->createNew(array_slice($this->elements, $number)); } public function dropRight($number) { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); } return $this->createNew(array_slice($this->elements, 0, -1 * $number)); } public function dropWhile($callable) { for ($i=0,$c=count($this->elements); $i<$c; $i++) { if (true !== call_user_func($callable, $this->elements[$i])) { break; } } return $this->createNew(array_slice($this->elements, $i)); } public function exists($callable) { foreach ($this as $elem) { if ($callable($elem) === true) { return true; } } return false; } public function count() { return count($this->elements); } public function getIterator() { return new \ArrayIterator($this->elements); } protected function createNew(array $elements) { return new static($elements); } } phpcollection/src/PhpCollection/AbstractCollection.php 0000644 00000002475 14736103327 0017247 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpCollection; use PhpOption\LazyOption; use PhpOption\Some; use PhpOption\None; abstract class AbstractCollection { public function contains($searchedElem) { foreach ($this as $elem) { if ($elem === $searchedElem) { return true; } } return false; } public function find($callable) { $self = $this; return new LazyOption(function() use ($callable, $self) { foreach ($self as $elem) { if (call_user_func($callable, $elem) === true) { return new Some($elem); } } return None::create(); }); } } phpcollection/src/PhpCollection/ObjectBasicsHandler.php 0000644 00000001241 14736103327 0017307 0 ustar 00 <?php namespace PhpCollection; /** * Interface for external handlers that provide ObjectBasics functionality. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface ObjectBasicsHandler { /** * @param object $object This object is guaranteed to be of the type the handler was registered for. * @return string|integer */ public function hash($object); /** * @param object $firstObject This object is guaranteed to be of the type the handler was registered for. * @param object $secondObject This might be an object of any class. * @return boolean */ public function equals($firstObject, $secondObject); } phpcollection/src/PhpCollection/SortedSequence.php 0000644 00000005420 14736103327 0016412 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpCollection; /** * A sequence with a fixed sort-order. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class SortedSequence extends AbstractSequence { private $sortFunc; public function __construct($sortFunc, array $elements = array()) { usort($elements, $sortFunc); parent::__construct($elements); $this->sortFunc = $sortFunc; } public function add($newElement) { $added = false; $newElements = array(); foreach ($this->elements as $element) { // We insert the new element before the first element that is greater than itself. if ( ! $added && (integer) call_user_func($this->sortFunc, $newElement, $element) < 0) { $newElements[] = $newElement; $added = true; } $newElements[] = $element; } if ( ! $added) { $newElements[] = $newElement; } $this->elements = $newElements; } public function addAll(array $addedElements) { usort($addedElements, $this->sortFunc); $newElements = array(); foreach ($this->elements as $element) { if ( ! empty($addedElements)) { foreach ($addedElements as $i => $newElement) { // If the currently looked at $newElement is not smaller than $element, then we can also conclude // that all other new elements are also not smaller than $element as we have ordered them before. if ((integer) call_user_func($this->sortFunc, $newElement, $element) > -1) { break; } $newElements[] = $newElement; unset($addedElements[$i]); } } $newElements[] = $element; } if ( ! empty($addedElements)) { foreach ($addedElements as $newElement) { $newElements[] = $newElement; } } $this->elements = $newElements; } protected function createNew(array $elements) { return new static($this->sortFunc, $elements); } } phpcollection/src/PhpCollection/SequenceInterface.php 0000644 00000013402 14736103327 0017051 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpCollection; use PhpOption\Option; /** * Interface for mutable sequences. * * Equality of elements in the sequence is established via a shallow comparison (===). * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface SequenceInterface extends CollectionInterface { /** * Returns the first element in the collection if available. * * @return Option */ public function first(); /** * Returns the last element in the collection if available. * * @return Option */ public function last(); /** * Returns all elements in this sequence. * * @return array */ public function all(); /** * Returns a new Sequence with all elements in reverse order. * * @return SequenceInterface */ public function reverse(); /** * Adds the elements of another sequence to this sequence. * * @param SequenceInterface $seq * * @return SequenceInterface */ public function addSequence(SequenceInterface $seq); /** * Returns the index of the passed element. * * @param mixed $elem * * @return integer the index (0-based), or -1 if not found */ public function indexOf($elem); /** * Returns the last index of the passed element. * * @param mixed $elem * @return integer the index (0-based), or -1 if not found */ public function lastIndexOf($elem); /** * Returns whether the given index is defined in the sequence. * * @param integer $index (0-based) * @return boolean */ public function isDefinedAt($index); /** * Returns the first index where the given callable returns true. * * @param callable $callable receives the element as first argument, and returns true, or false * * @return integer the index (0-based), or -1 if the callable returns false for all elements */ public function indexWhere($callable); /** * Returns the last index where the given callable returns true. * * @param callable $callable receives the element as first argument, and returns true, or false * * @return integer the index (0-based), or -1 if the callable returns false for all elements */ public function lastIndexWhere($callable); /** * Returns all indices of this collection. * * @return integer[] */ public function indices(); /** * Returns the element at the given index. * * @param integer $index (0-based) * * @return mixed */ public function get($index); /** * Adds an element to the sequence. * * @param mixed $elem * * @return void */ public function add($elem); /** * Removes the element at the given index, and returns it. * * @param integer $index * * @return mixed */ public function remove($index); /** * Adds all elements to the sequence. * * @param array $elements * * @return void */ public function addAll(array $elements); /** * Updates the value at the given index. * * @param integer $index * @param mixed $value * * @return void */ public function update($index, $value); /** * Returns a new sequence by omitting the given number of elements from the beginning. * * If the passed number is greater than the available number of elements, all will be removed. * * @param integer $number * * @return SequenceInterface */ public function drop($number); /** * Returns a new sequence by omitting the given number of elements from the end. * * If the passed number is greater than the available number of elements, all will be removed. * * @param integer $number * * @return SequenceInterface */ public function dropRight($number); /** * Returns a new sequence by omitting elements from the beginning for as long as the callable returns true. * * @param callable $callable Receives the element to drop as first argument, and returns true (drop), or false (stop). * * @return SequenceInterface */ public function dropWhile($callable); /** * Creates a new collection by taking the given number of elements from the beginning * of the current collection. * * If the passed number is greater than the available number of elements, then all elements * will be returned as a new collection. * * @param integer $number * * @return CollectionInterface */ public function take($number); /** * Creates a new collection by taking elements from the current collection * for as long as the callable returns true. * * @param callable $callable * * @return CollectionInterface */ public function takeWhile($callable); /** * Creates a new collection by applying the passed callable to all elements * of the current collection. * * @param callable $callable * @return CollectionInterface */ public function map($callable); } phpcollection/src/PhpCollection/AbstractMap.php 0000644 00000016023 14736103327 0015663 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpCollection; use PhpOption\Some; use PhpOption\None; /** * A simple map implementation which basically wraps an array with an object oriented interface. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class AbstractMap extends AbstractCollection implements \IteratorAggregate, MapInterface { protected $elements; public function __construct(array $elements = array()) { $this->elements = $elements; } public function set($key, $value) { $this->elements[$key] = $value; } public function exists($callable) { foreach ($this as $k => $v) { if ($callable($k, $v) === true) { return true; } } return false; } /** * Sets all key/value pairs in the map. * * @param array $kvMap * * @return void */ public function setAll(array $kvMap) { $this->elements = array_merge($this->elements, $kvMap); } public function addMap(MapInterface $map) { foreach ($map as $k => $v) { $this->elements[$k] = $v; } } public function get($key) { if (isset($this->elements[$key])) { return new Some($this->elements[$key]); } return None::create(); } public function all() { return $this->elements; } public function remove($key) { if ( ! isset($this->elements[$key])) { throw new \InvalidArgumentException(sprintf('The map has no key named "%s".', $key)); } $element = $this->elements[$key]; unset($this->elements[$key]); return $element; } public function clear() { $this->elements = array(); } public function first() { if (empty($this->elements)) { return None::create(); } $elem = reset($this->elements); return new Some(array(key($this->elements), $elem)); } public function last() { if (empty($this->elements)) { return None::create(); } $elem = end($this->elements); return new Some(array(key($this->elements), $elem)); } public function contains($elem) { foreach ($this->elements as $existingElem) { if ($existingElem === $elem) { return true; } } return false; } public function containsKey($key) { return isset($this->elements[$key]); } public function isEmpty() { return empty($this->elements); } /** * Returns a new filtered map. * * @param callable $callable receives the element and must return true (= keep), or false (= remove). * * @return AbstractMap */ public function filter($callable) { return $this->filterInternal($callable, true); } /** * Returns a new filtered map. * * @param callable $callable receives the element and must return true (= remove), or false (= keep). * * @return AbstractMap */ public function filterNot($callable) { return $this->filterInternal($callable, false); } /** * @param callable $callable * @param boolean $booleanKeep */ private function filterInternal($callable, $booleanKeep) { $newElements = array(); foreach ($this->elements as $k => $element) { if ($booleanKeep !== call_user_func($callable, $element)) { continue; } $newElements[$k] = $element; } return $this->createNew($newElements); } public function foldLeft($initialValue, $callable) { $value = $initialValue; foreach ($this->elements as $elem) { $value = call_user_func($callable, $value, $elem); } return $value; } public function foldRight($initialValue, $callable) { $value = $initialValue; foreach (array_reverse($this->elements) as $elem) { $value = call_user_func($callable, $elem, $value); } return $value; } public function dropWhile($callable) { $newElements = array(); $stopped = false; foreach ($this->elements as $k => $v) { if ( ! $stopped) { if (call_user_func($callable, $k, $v) === true) { continue; } $stopped = true; } $newElements[$k] = $v; } return $this->createNew($newElements); } public function drop($number) { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); } return $this->createNew(array_slice($this->elements, $number, null, true)); } public function dropRight($number) { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); } return $this->createNew(array_slice($this->elements, 0, -1 * $number, true)); } public function take($number) { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); } return $this->createNew(array_slice($this->elements, 0, $number, true)); } public function takeWhile($callable) { $newElements = array(); foreach ($this->elements as $k => $v) { if (call_user_func($callable, $k, $v) !== true) { break; } $newElements[$k] = $v; } return $this->createNew($newElements); } public function find($callable) { foreach ($this->elements as $k => $v) { if (call_user_func($callable, $k, $v) === true) { return new Some(array($k, $v)); } } return None::create(); } public function keys() { return array_keys($this->elements); } public function values() { return array_values($this->elements); } public function count() { return count($this->elements); } public function getIterator() { return new \ArrayIterator($this->elements); } protected function createNew(array $elements) { return new static($elements); } } phpcollection/src/PhpCollection/SortableInterface.php 0000644 00000001504 14736103327 0017054 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpCollection; /** * Interface for sortable collections. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface SortableInterface { public function sortWith($callable); } phpcollection/src/PhpCollection/CollectionInterface.php 0000644 00000005325 14736103327 0017401 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpCollection; /** * Basic interface which adds some behaviors, and a few methods common to all collections. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface CollectionInterface extends \Traversable, \Countable { /** * Returns whether this collection contains the passed element. * * @param mixed $elem * * @return boolean */ public function contains($elem); /** * Returns whether the collection is empty. * * @return boolean */ public function isEmpty(); /** * Returns a filtered collection of the same type. * * Removes all elements for which the provided callable returns false. * * @param callable $callable receives an element of the collection and must return true (= keep) or false (= remove). * * @return CollectionInterface */ public function filter($callable); /** * Returns a filtered collection of the same type. * * Removes all elements for which the provided callable returns true. * * @param callable $callable receives an element of the collection and must return true (= remove) or false (= keep). * * @return CollectionInterface */ public function filterNot($callable); /** * Applies the callable to an initial value and each element, going left to right. * * @param mixed $initialValue * @param callable $callable receives the current value (the first time this equals $initialValue) and the element * * @return mixed the last value returned by $callable, or $initialValue if collection is empty. */ public function foldLeft($initialValue, $callable); /** * Applies the callable to each element, and an initial value, going right to left. * * @param mixed $initialValue * @param callable $callable receives the element, and the current value (the first time this equals $initialValue). * @return mixed the last value returned by $callable, or $initialValue if collection is empty. */ public function foldRight($initialValue, $callable); } phpcollection/src/PhpCollection/ObjectBasicsHandler/DateTimeHandler.php 0000644 00000001417 14736103327 0022306 0 ustar 00 <?php namespace PhpCollection\ObjectBasicsHandler; use PhpCollection\ObjectBasicsHandler; class DateTimeHandler implements ObjectBasicsHandler { public function hash($object) { if ( ! $object instanceof \DateTime) { throw new \LogicException('$object must be an instance of \DateTime.'); } return $object->getTimestamp(); } public function equals($thisObject, $otherObject) { if ( ! $thisObject instanceof \DateTime) { throw new \LogicException('$thisObject must be an instance of \DateTime.'); } if ( ! $otherObject instanceof \DateTime) { return false; } return $thisObject->format(\DateTime::ISO8601) === $otherObject->format(\DateTime::ISO8601); } } phpcollection/src/PhpCollection/ObjectBasicsHandler/IdentityHandler.php 0000644 00000000466 14736103327 0022406 0 ustar 00 <?php namespace PhpCollection\ObjectBasicsHandler; use PhpCollection\ObjectBasicsHandler; class IdentityHandler implements ObjectBasicsHandler { public function hash($object) { return spl_object_hash($object); } public function equals($a, $b) { return $a === $b; } } phpcollection/src/PhpCollection/ObjectBasicsHandlerRegistry.php 0000644 00000005353 14736103327 0021050 0 ustar 00 <?php namespace PhpCollection; use PhpCollection\ObjectBasicsHandler\IdentityHandler; /** * Registry for handlers that provide ObjectBasics functionality for classes. * * You want to register a handler if you cannot implement the ObjectBasics interface, for example * because a class is provided by a third-party package, or built into PHP. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ abstract class ObjectBasicsHandlerRegistry { private static $handlers = array( 'DateTime' => 'PhpCollection\\ObjectBasicsHandler\\DateTimeHandler', ); private static $defaultObjectHandler; private static $aliases = array(); /** * Defines an alias. * * $aliasClass must be a sub-type (extend or implement) $handlingClass; otherwise you will run into trouble. * * Aliases can only be one level deep, * * i.e. aliasClass -> handlingClass is supported, * but aliasClass -> anotherAliasClass -> handlingClass is not. * * @param string $handlingClass The class that should be aliased, i.e. MyDateTime * @param string $aliasClass The class that should be used instead, i.e. DateTime */ public static function addAliasFor($handlingClass, $aliasClass) { self::$aliases[$handlingClass] = $aliasClass; } public static function addHandlerFor($handlingClass, $handlerInstanceOrClassName) { if ( ! $handlerInstanceOrClassName instanceof ObjectBasicsHandler && ! is_string($handlerInstanceOrClassName)) { throw new \LogicException('$handler must be an instance of ObjectBasicsHandler, or a string referring to the handlers class.'); } self::$handlers[$handlingClass] = $handlerInstanceOrClassName; } public static function getHandler($className) { if (isset(self::$aliases[$className])) { $className = self::$aliases[$className]; } if ( ! isset(self::$handlers[$className])) { if (self::$defaultObjectHandler === null) { self::$defaultObjectHandler = new IdentityHandler(); } return self::$defaultObjectHandler; } if (self::$handlers[$className] instanceof ObjectBasicsHandler) { return self::$handlers[$className]; } if (is_string(self::$handlers[$className])) { $handlerClass = self::$handlers[$className]; return self::$handlers[$className] = new $handlerClass(); } throw new \LogicException(sprintf( 'Unknown handler type ("%s") for class "%s" - should never be reached.', gettype(self::$handlers[$className]), $className )); } private final function __construct() { } } phpcollection/src/PhpCollection/EntityLikeObject.php 0000644 00000000657 14736103327 0016700 0 ustar 00 <?php namespace PhpCollection; /** * Implementation for ObjectBasics for entity-like objects. * * Two objects are considered equal if they refer to the same instance. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ trait EntityLikeObject { public function hash() { return spl_object_hash($this); } public function equals(ObjectBasics $other) { return $this === $other; } } phpcollection/README.md 0000644 00000000162 14736103327 0010673 0 ustar 00 PHP Collection ============== Learn more about it in its [documentation](http://jmsyst.com/libs/php-collection). phpcollection/LICENSE 0000644 00000026134 14736103327 0010430 0 ustar 00 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.