├── tests ├── .gitkeep ├── fixtures │ ├── Dockerfile-eventlog │ ├── history-seed.yml │ ├── Dockerfile-nginx │ ├── scalemanager_eventlog.sql │ ├── Dockerfile-php │ ├── default.conf │ └── docker-compose.yml ├── unit │ └── CollectorTest.php └── integration │ └── HistoryDBTest.php ├── .gitignore ├── sql └── history.sql ├── src ├── CpuScaleCommand.php ├── MemoryScaleCommand.php ├── CommandInterface.php ├── instance-api │ ├── conf │ │ ├── conf.inc.php │ │ └── conf.inc.php-template │ ├── lib │ │ ├── storageRescale.class.php │ │ ├── cpuRescale.class.php │ │ ├── ramRescale.class.php │ │ ├── rescaleBuilder.class.php │ │ └── IsacApiConnector.class.php │ ├── api │ │ └── swagger.yaml │ └── index.php ├── public │ └── index.php ├── ScaleCommandInterface.php ├── HistoryInterface.php ├── api │ └── collector.yml ├── Collector.php ├── ScaleCommand.php ├── State.php ├── Query.php ├── Rule.php └── History.php ├── docs ├── decisions.md ├── example-rules.md └── overview.md ├── composer.json ├── LICENSE ├── README.md └── composer.lock /tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | .idea -------------------------------------------------------------------------------- /tests/fixtures/Dockerfile-eventlog: -------------------------------------------------------------------------------- 1 | FROM mysql:latest 2 | EXPOSE 3306 3 | ADD scalemanager_eventlog.sql /docker-entrypoint-initdb.d 4 | -------------------------------------------------------------------------------- /tests/fixtures/history-seed.yml: -------------------------------------------------------------------------------- 1 | history: 2 | - id: 1 3 | timestamp: 123450000 4 | type: "memory" 5 | instance: "reseller/1" 6 | value: 1024 7 | - id: 2 8 | timestamp: 123450001 9 | type: "cpu" 10 | instance: "reseller/1" 11 | value: 10 12 | -------------------------------------------------------------------------------- /tests/fixtures/Dockerfile-nginx: -------------------------------------------------------------------------------- 1 | # Set the base image 2 | FROM nginx:latest 3 | # Set Timezone to Europe/Berlin 4 | RUN rm /etc/localtime \ 5 | && ln -s /usr/share/zoneinfo/Europe/Berlin /etc/localtime 6 | # Expose http Port 7 | EXPOSE 80 8 | # Add Config Files 9 | ADD default.conf /etc/nginx/conf.d 10 | -------------------------------------------------------------------------------- /sql/history.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `history` ( 2 | `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 3 | `timestamp` INT UNSIGNED NOT NULL, 4 | `type` VARCHAR(255) NOT NULL, 5 | `instance` VARCHAR(255) NOT NULL, 6 | `value` VARCHAR(255) NOT NULL, 7 | PRIMARY KEY (`id`), 8 | INDEX `Query` (`timestamp` ASC, `type` ASC, `instance` ASC)); 9 | -------------------------------------------------------------------------------- /src/CpuScaleCommand.php: -------------------------------------------------------------------------------- 1 | 80% for more than 5 minutes, ram +1gb 4 | - If systemload > x for more than y minutes, cpu +1core 5 | - If systemload > x for more than 2*y minutes, cpu -1 core 6 | - If systemload > x for more than 2*y minutes, trigger alert (removing the last cpu is blocked by the isac api) 7 | - If ram usage < x for more than y minutes, ram -1gb 8 | - If systemload < x for more than y minutes, cpu -1core 9 | -------------------------------------------------------------------------------- /tests/fixtures/scalemanager_eventlog.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE `scalemanager_eventlog`; 2 | USE `scalemanager_eventlog`; 3 | CREATE TABLE `history` ( 4 | `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 5 | `timestamp` INT UNSIGNED NOT NULL, 6 | `type` VARCHAR(255) NOT NULL, 7 | `instance` VARCHAR(255) NOT NULL, 8 | `value` VARCHAR(255) NOT NULL, 9 | PRIMARY KEY (`id`), 10 | INDEX `Query` (`timestamp` ASC, `type` ASC, `instance` ASC) 11 | ); 12 | -------------------------------------------------------------------------------- /src/CommandInterface.php: -------------------------------------------------------------------------------- 1 | post('/state', function (Request $request, Response $response) { 13 | $response = $response->withStatus(202); 14 | $pdo = new PDO('mysql:host=scalemanager-eventlog-db;dbname=scalemanager_eventlog', 'root'); 15 | $collector = new Collector(new History($pdo)); 16 | $collector->collect($request); 17 | return $response; 18 | }); 19 | $app->run(); -------------------------------------------------------------------------------- /src/ScaleCommandInterface.php: -------------------------------------------------------------------------------- 1 | adjustValue($instance->storage, $type, $diffValue); 23 | $instance->storage = $storageNew; 24 | return $instance; 25 | } 26 | } -------------------------------------------------------------------------------- /src/instance-api/lib/cpuRescale.class.php: -------------------------------------------------------------------------------- 1 | adjustValue($instance->cpu, $type, $diffValue); 25 | $instance->cpu = $cpuNew; 26 | return $instance; 27 | } 28 | } -------------------------------------------------------------------------------- /src/HistoryInterface.php: -------------------------------------------------------------------------------- 1 | adjustValue($instance->ram, $type, $diffValue); 25 | $instance->ram = $ramNew; 26 | return $instance; 27 | } 28 | } -------------------------------------------------------------------------------- /tests/fixtures/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | index index.php index.html; 4 | server_name localhost; 5 | error_log /var/log/nginx/error.log; 6 | access_log /var/log/nginx/access.log; 7 | root /var/www/html/src/public/; 8 | 9 | location = /favicon.ico { 10 | rewrite ^/favicon\.ico$ $1/extern/favicon.php last; 11 | } 12 | location / { 13 | root /var/www/html/src/public/; 14 | index index.html index.php; 15 | try_files $uri $uri/ /index.php?$is_args$args; 16 | } 17 | location ~ \.php$ { 18 | root /var/www/html/src/public/; 19 | try_files $uri @router; 20 | fastcgi_pass scalemanager-php:9000; 21 | fastcgi_index index.php; 22 | fastcgi_param SCRIPT_FILENAME /var/www/html/src/public/$fastcgi_script_name; 23 | fastcgi_buffers 16 32k; 24 | fastcgi_buffer_size 32k; 25 | include fastcgi_params; 26 | } 27 | location @router{ 28 | rewrite ^\/(.*)\.php /index.php/$1; 29 | } 30 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Tobias Weichart 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/instance-api/lib/rescaleBuilder.class.php: -------------------------------------------------------------------------------- 1 | createMock(HistoryInterface::class); 24 | 25 | $history 26 | ->expects($this->once()) 27 | ->method('saveEvent') 28 | ; 29 | $collector = new Collector($history); 30 | $request = $this->createMock(Request::class); 31 | 32 | $request 33 | ->expects($this->any()) 34 | ->method('getBody') 35 | ->willReturn(json_encode([ 36 | 'instance' => 'reseller/123', 37 | 'type' => 'memory', 38 | 'value' => '20', 39 | 'timestamp' => '123123123', 40 | ])) 41 | ; 42 | $collector->collect($request); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/api/collector.yml: -------------------------------------------------------------------------------- 1 | swagger: '2.0' 2 | info: 3 | title: ScaleManager Collector API 4 | description: ScaleManager Collector API for collecting data from the instances 5 | version: "1.0.0" 6 | schemes: 7 | - https 8 | basePath: /v1 9 | produces: 10 | - application/json 11 | paths: 12 | /state: 13 | post: 14 | summary: Collects data for the ScaleManager for further usage 15 | description: Collects data from various instances to further use it in the ScaleManager. 16 | parameters: 17 | - name: type 18 | in: body 19 | schema: 20 | $ref: '#/definitions/State' 21 | description: Current state 22 | required: true 23 | responses: 24 | 202: 25 | description: State was accepted 26 | definitions: 27 | State: 28 | type: object 29 | properties: 30 | type: 31 | type: string 32 | description: Type of the state, e.g. memory or cpu-load. 33 | value: 34 | type: string 35 | description: The value the state has. In case of memory its the actual size in KB. 36 | instance: 37 | type: string 38 | description: The ID of the instance. 39 | timestamp: 40 | type: integer 41 | format: int32 42 | description: The timestamp the state was recorded at. -------------------------------------------------------------------------------- /tests/fixtures/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | scalemanager-api: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile-nginx 7 | ports: 8 | - "82:80" 9 | links: 10 | - scalemanager-php 11 | volumes: 12 | - "./:/var/www/html" 13 | scalemanager-php: 14 | build: 15 | context: . 16 | dockerfile: Dockerfile-php 17 | ports: 18 | - "9002:9000" 19 | volumes: 20 | - "./:/var/www/html" 21 | scalemanager-eventlog-db: 22 | build: 23 | context: . 24 | dockerfile: Dockerfile-eventlog 25 | ports: 26 | - "3308:3306" 27 | environment: 28 | - MYSQL_USER=scalemanager-eventlog 29 | - MYSQL_PASSWORD=scalemanager-eventlog 30 | - MYSQL_DATABASE=scalemanager-eventlog 31 | - MYSQL_ROOT_PASSWORD= 32 | - MYSQL_ALLOW_EMPTY_PASSWORD=true 33 | scalemanager-actionlog-db: 34 | image: mysql/mysql-server 35 | ports: 36 | - "3310:3306" 37 | environment: 38 | - MYSQL_USER=scalemanager-actionlog 39 | - MYSQL_PASSWORD=scalemanager-actionlog 40 | - MYSQL_DATABASE=scalemenager-actionlog 41 | - MYSQL_ROOT_PASSWORD= 42 | - MYSQL_ALLOW_EMPTY_PASSWORD=true 43 | -------------------------------------------------------------------------------- /src/Collector.php: -------------------------------------------------------------------------------- 1 | history = $history; 35 | } 36 | 37 | /** 38 | * Collect a State 39 | * 40 | * @param Request $request The request containing the state information 41 | * 42 | * @return void 43 | */ 44 | public function collect(Request $request) 45 | { 46 | $payload = $this->getPayload($request); 47 | $state = new State($payload->instance, $payload->type, $payload->value, $payload->timestamp); 48 | $this->history->saveEvent($state); 49 | } 50 | 51 | /** 52 | * Get the payload from the request 53 | * 54 | * @param Request $request The request containing the state information 55 | * 56 | * @return \stdClass 57 | */ 58 | private function getPayload(Request $request): \stdClass 59 | { 60 | return json_decode($request->getBody()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/instance-api/api/swagger.yaml: -------------------------------------------------------------------------------- 1 | # this is an example of the Uber API 2 | # as a demonstration of an API spec in YAML 3 | swagger: '2.0' 4 | info: 5 | title: Scale Manager Instance API 6 | description: Trigger instance actions 7 | version: "1.0.0" 8 | # the domain of the service 9 | # array of all schemes that your API supports 10 | schemes: 11 | - https 12 | # will be prefixed to all paths 13 | basePath: / 14 | produces: 15 | - application/json 16 | paths: 17 | /instance: 18 | post: 19 | summary: Instance actions 20 | description: | 21 | Endpoint for modifying instance parameters like ram, cpu and storage. 22 | parameters: 23 | - name: instance 24 | in: query 25 | description: Instance IP to be resized 26 | required: true 27 | type: string 28 | - name: type 29 | in: query 30 | description: resize type. 31 | required: true 32 | type: string 33 | enum: ["abs", "rel", "percent"] 34 | - name: value 35 | in: query 36 | description: value. 37 | required: true 38 | type: string 39 | - name: component 40 | in: query 41 | description: Component to be resized. 42 | required: true 43 | type: string 44 | enum: ["cpu", "ram", "storage"] 45 | responses: 46 | 200: 47 | description: Action successfully triggered 48 | 406: 49 | description: Request could not be executed 50 | 51 | -------------------------------------------------------------------------------- /docs/overview.md: -------------------------------------------------------------------------------- 1 | # Scale Manager Overview 2 | 3 | _Insert photo here_ 4 | 5 | ## Dataflow 6 | 7 | 8 | ###Instance 9 | The instances sends the collected states to the collector. 10 | The payload includes: 11 | - type (ram, load, storage_usage) 12 | - value 13 | - timestamp 14 | 15 | ###Collector 16 | The collector sends the data to the history and puts the data (state) in the queue for processing by the manager. 17 | 18 | ###History 19 | The history is responsible for managing the eventlog. It stores any new states that were sent from the collector. 20 | History data stored: 21 | - type 22 | - value 23 | - timestamp 24 | - instance 25 | 26 | Furthermore it provides a function for querying the eventlog data and returns a boolean if there is a match. 27 | Required parameter for the query: 28 | - instance 29 | - timestamp_start 30 | - timestamp_end 31 | - value 32 | - condition 33 | 34 | ###Manager 35 | The manager polls the queue for new events. The event type is used to check if any rule applies. 36 | First the actionlog will be checked if there is any action of the same type active. 37 | If an action of the same type is active the event will be skipped. 38 | Otherwise all applying rules will be loaded. If the rule applies an entry in the action log will be created and the command dispatched. 39 | 40 | Command (each class has an action, e.g. cpu upsize): 41 | - instance 42 | - type (abs, rel, percent) 43 | - value 44 | 45 | Actionlog: 46 | - command 47 | - instance 48 | - timestamp_start 49 | - timestamp_end 50 | - event 51 | 52 | ###Cleaner 53 | The cleaner processes the action log to create new state messages to action which are in a possible faile state. 54 | Deletes old eventlog entries and aggregates them in an archive 55 | -------------------------------------------------------------------------------- /src/ScaleCommand.php: -------------------------------------------------------------------------------- 1 | instance = $instance; 62 | $this->type = $type; 63 | $this->value = $value; 64 | } 65 | 66 | /** 67 | * Get the type of change, i.e., one of the ScaleCommand constants 68 | * 69 | * @return string The type 70 | */ 71 | public function getType(): string 72 | { 73 | return $this->type; 74 | } 75 | 76 | /** 77 | * Get the value 78 | * 79 | * @return float The value 80 | */ 81 | public function getValue(): float 82 | { 83 | return $this->value; 84 | } 85 | 86 | /** 87 | * Get the instance ID 88 | * 89 | * @return string The instance ID 90 | */ 91 | public function getInstance(): string 92 | { 93 | return $this->instance; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/State.php: -------------------------------------------------------------------------------- 1 | instance = $instance; 55 | $this->type = $type; 56 | $this->value = $value; 57 | $this->timeStamp = $timeStamp; 58 | } 59 | 60 | /** 61 | * Get the type of the state, e.g., memory, cpu-load, ... 62 | * 63 | * @return string The type of the state 64 | */ 65 | public function getType(): string 66 | { 67 | return $this->type; 68 | } 69 | 70 | /** 71 | * Get the state value 72 | * 73 | * @return mixed The state value 74 | */ 75 | public function getValue() 76 | { 77 | return $this->value; 78 | } 79 | 80 | /** 81 | * Get the instance ID 82 | * 83 | * @return string The instance ID 84 | */ 85 | public function getInstance(): string 86 | { 87 | return $this->instance; 88 | } 89 | 90 | /** 91 | * Get the timestamp of the measurement 92 | * 93 | * @return int The timestamp, number of seconds since 00:00:00 UTC on January 1, 1970 94 | */ 95 | public function getTimeStamp(): int 96 | { 97 | return $this->timeStamp; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Query.php: -------------------------------------------------------------------------------- 1 | instance = $instance; 61 | $this->type = $type; 62 | $this->operator = $operator; 63 | $this->value = $value; 64 | $this->timeStart = $timeStart; 65 | $this->timeEnd = $timeEnd; 66 | } 67 | 68 | /** 69 | * @return string 70 | */ 71 | public function getInstance(): string 72 | { 73 | return $this->instance; 74 | } 75 | 76 | /** 77 | * @return string 78 | */ 79 | public function getType(): string 80 | { 81 | return $this->type; 82 | } 83 | 84 | /** 85 | * @return string 86 | */ 87 | public function getOperator(): string 88 | { 89 | return $this->operator; 90 | } 91 | 92 | /** 93 | * @return string 94 | */ 95 | public function getValue(): string 96 | { 97 | return $this->value; 98 | } 99 | 100 | /** 101 | * @return int 102 | */ 103 | public function getTimeStart(): int 104 | { 105 | return $this->timeStart; 106 | } 107 | 108 | /** 109 | * @return int 110 | */ 111 | public function getTimeEnd(): int 112 | { 113 | return $this->timeEnd; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/instance-api/index.php: -------------------------------------------------------------------------------- 1 | post('/instance', function ($request, $response, $args) { 19 | 20 | $isacConnector = new IsacApiConnector(); 21 | $isacConnector->authenticate(); 22 | $data = $request->getParsedBody(); 23 | 24 | $instance = $isacConnector->findInstanceByIP($data['instance']); 25 | 26 | $component = $data['component']; 27 | 28 | $newValue = null; 29 | 30 | switch ($component) { 31 | case "cpu": 32 | $cpuResizer = new cpuRescale(); 33 | $newValue = $cpuResizer->calculateValues($instance, $data['type'], $data['value']); 34 | break; 35 | 36 | case "ram": 37 | $ramResizer = new ramRescale(); 38 | $newValue = $ramResizer->calculateValues($instance, $data['type'], $data['value']); 39 | break; 40 | 41 | case "storage": 42 | $storageResizer = new storageRescale(); 43 | $newValue = $storageResizer->calculateValues($instance, $data['type'], $data['value']); 44 | break; 45 | default: 46 | $response = $response->withStatus(401); 47 | return $response; 48 | } 49 | 50 | 51 | if ($newValue != null) { 52 | $resizeResult = $isacConnector->resizeInstance($newValue); 53 | 54 | if (!$resizeResult) { 55 | $response = $response->withStatus(400); 56 | return $response; 57 | } 58 | $response = $response->withStatus(200); 59 | return $response; 60 | 61 | 62 | } else { 63 | $response = $response->withStatus(401); 64 | return $response; 65 | } 66 | 67 | }); 68 | 69 | 70 | 71 | $app->run(); 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScaleManager 2 | 3 | The ScaleManager oversees multiple VM instances and scales them correpsonding to a predefined ruleset. 4 | 5 | It consists of multiple micro-services: 6 | * **Daemon** service running on multiple VM instances reporting states in a predefined period of time 7 | * **Daemon-API** receiving commands from the manager, builds commands usable by the environment the api runs on for the needed call (e.g. resize API-Call to Hoster) 8 | * **Collectors** collecting all the data from the daemons, sending the data to the history and the queue which serves the data to the manager 9 | * **History** receives data to store it in the connected EventLog (MySQL Database) 10 | * **Queue** stream based queue to provide the event data to the manager for an ordered processing 11 | * **Manager** this component manages the information retrieved by the queue. Based on predefined rules it desides whether there is any action to take or not. 12 | * A question to the history will be sent to retrieve informations for the rule matching the event coming from the queue 13 | * The answer helps to deside whether a command for resizing an instance is triggered or not. 14 | * Triggered commands will be inserted into the ActionLog, blocking any further rules that match the same event type to trigger the next command execution 15 | * After inserting into the ActionLog the command will be sent to the Instance or API managing the instances to take further actions 16 | * If the command could not be executed the manager also has the possibility to generate alerts, which can be retrieved via different endpoints (mail, chat, etc.) 17 | * **Cleaner** The cleaner moves old date from the EventLog and the ActionLog to the archive with the goal to keep the index on those databases small 18 | 19 | ## Running Tests 20 | 21 | ### Unit Tests 22 | 23 | In the project root directory, enter 24 | 25 | ```bash 26 | $ vendor/bin/phpunit --bootstrap vendor/autoload.php tests/unit 27 | ``` 28 | 29 | ### Integration Tests 30 | 31 | Before you can run the integration tests, you have to setup the expected environment. You need a recent version of `docker-compose` (> 1.10)for that. 32 | 33 | Start the environment: 34 | 35 | ```bash 36 | $ cd tests/fixtures 37 | $ docker-compose up -d 38 | $ cd ../.. 39 | ``` 40 | 41 | Run the tests: 42 | 43 | ```bash 44 | $ vendor/bin/phpunit --bootstrap vendor/autoload.php tests/integration 45 | ``` 46 | 47 | Stop the environment: 48 | 49 | ```bash 50 | $ cd tests/fixtures 51 | $ docker-compose stop 52 | $ cd ../.. 53 | ``` 54 | -------------------------------------------------------------------------------- /src/Rule.php: -------------------------------------------------------------------------------- 1 | operator $this->value 32 | * 33 | * @var string 34 | */ 35 | private $operator; 36 | 37 | /** 38 | * Minimum duration of the state needed to trigger the rule 39 | * 40 | * @var int Number of seconds 41 | */ 42 | private $duration; 43 | 44 | /** 45 | * The command to be issued 46 | * 47 | * @var CommandInterface 48 | */ 49 | private $command; 50 | 51 | /** 52 | * Rule constructor. 53 | * 54 | * @param string $type The state type 55 | * @param mixed $value The state threshold value 56 | * @param string $operator The comparision operator 57 | * @param int $duration The expected duration 58 | * @param CommandInterface $command The command to be issued 59 | */ 60 | public function __construct(string $type, $value, string $operator, int $duration, CommandInterface $command) 61 | { 62 | $this->type = $type; 63 | $this->value = $value; 64 | $this->operator = $operator; 65 | $this->duration = $duration; 66 | $this->command = $command; 67 | } 68 | 69 | /** 70 | * Get the state type 71 | * 72 | * @return string 73 | */ 74 | public function getType(): string 75 | { 76 | return $this->type; 77 | } 78 | 79 | /** 80 | * Get the state value 81 | * 82 | * @return mixed 83 | */ 84 | public function getValue() 85 | { 86 | return $this->value; 87 | } 88 | 89 | /** 90 | * Get the comparision operator 91 | * 92 | * @return string 93 | */ 94 | public function getOperator(): string 95 | { 96 | return $this->operator; 97 | } 98 | 99 | /** 100 | * Get the expected continuance 101 | * 102 | * @return int 103 | */ 104 | public function getDuration(): int 105 | { 106 | return $this->duration; 107 | } 108 | 109 | /** 110 | * Get the command 111 | * 112 | * @return CommandInterface 113 | */ 114 | public function getCommand(): CommandInterface 115 | { 116 | return $this->command; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /tests/integration/HistoryDBTest.php: -------------------------------------------------------------------------------- 1 | pdo = new PDO($this->dsn, $this->user); 29 | } 30 | catch (\PDOException $e) { 31 | $this->markTestSkipped('The PDO connection is not available.'); 32 | } 33 | 34 | $this->pdo->query("TRUNCATE `history`"); 35 | $this->pdo->query("INSERT INTO `history` 36 | (`instance`, `type`, `value`, `timestamp`) 37 | VALUES 38 | ('reseller/123', 'memory', 1024, 100), 39 | ('reseller/123', 'memory', 1000, 200), 40 | ('reseller/123', 'memory', 1048, 300) 41 | "); 42 | } 43 | 44 | /** 45 | * @testdox saveEvent() adds a record to the history table 46 | */ 47 | public function testSaveEvent() 48 | { 49 | $history = new History($this->pdo); 50 | 51 | $state = new State('reseller/123', 'memory', 1024, 100); 52 | 53 | $originalCount = $this->getRecordCount('history'); 54 | $result = $history->saveEvent($state); 55 | 56 | $this->assertTrue($result, 'Saving state failed'); 57 | 58 | $this->assertRecordCount('history', $originalCount + 1, 'Number of records is not as expected'); 59 | } 60 | 61 | public function queryDataProvider() 62 | { 63 | return [ 64 | 'no incidents at all' => [400, 500, false] /**/, 65 | 'no matching incidents' => [101, 299, false] /* 200:1000 */, 66 | 'only matching incidents' => [201, 400, true] /* 300:1048 */, 67 | 'both matching and not matching incidents' => [0, 400, false] /* 100:1024, 200:1000, 300:1048 */, 68 | ]; 69 | } 70 | 71 | /** 72 | * @dataProvider queryDataProvider 73 | * 74 | * @testdox queryEventLog() returns the defined value (true or false), when encountering 75 | */ 76 | public function testQuery(int $timeStart, int $timeEnd, bool $expected) 77 | { 78 | $history = new History($this->pdo); 79 | 80 | $query = new Query('reseller/123', 'memory', '>=', 1024, $timeStart, $timeEnd); 81 | $result = $history->queryEventLog($query); 82 | 83 | $this->assertEquals($expected, $result); 84 | } 85 | 86 | protected function getRecordCount(string $table): int 87 | { 88 | $result = $this->pdo->query("SELECT COUNT(*) FROM `$table`"); 89 | 90 | return $result->fetchColumn(0); 91 | } 92 | 93 | protected function assertRecordCount(string $table, int $count, $messsage = '') 94 | { 95 | $this->assertEquals($count, $this->getRecordCount($table), $messsage); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/History.php: -------------------------------------------------------------------------------- 1 | connection = $connection; 31 | } 32 | 33 | /** 34 | * Save an event to the history storage. 35 | * 36 | * @param State $state The state to store 37 | * 38 | * @return bool 39 | */ 40 | public function saveEvent(State $state): bool 41 | { 42 | $query = $this->connection->prepare( 43 | 'INSERT INTO history (`timestamp`, `type`, `instance`, `value`) VALUES(:timestamp, :type, :instance, :value);' 44 | ); 45 | 46 | $instance = $state->getInstance(); 47 | $type = $state->getType(); 48 | $value = $state->getValue(); 49 | $timeStamp = $state->getTimeStamp(); 50 | 51 | $query->bindParam(':instance', $instance); 52 | $query->bindParam(':type', $type); 53 | $query->bindParam(':value', $value); 54 | $query->bindParam(':timestamp', $timeStamp); 55 | 56 | return $query->execute(); 57 | } 58 | 59 | /** 60 | * Ask the Event Log, if a condition persisted for a given time range 61 | * 62 | * @param Query $query The Query 63 | * 64 | * @return bool True if the condition was always true in the given time range. 65 | * @throws \Exception 66 | */ 67 | public function queryEventLog(Query $query): bool 68 | { 69 | $instance = $query->getInstance(); 70 | $type = $query->getType(); 71 | $operator = $query->getOperator(); 72 | $value = $query->getValue(); 73 | $timeStart = $query->getTimeStart(); 74 | $timeEnd = $query->getTimeEnd(); 75 | 76 | $query = $this->connection->prepare( 77 | "SELECT AVG(`value`) AS `average`, SUM(`match`) AS `match`, SUM(`nomatch`) AS `nomatch` 78 | FROM ( 79 | SELECT 80 | `value`, 81 | CASE WHEN `value` $operator :value THEN 1 ELSE 0 END AS `match`, 82 | CASE WHEN `value` $operator :value THEN 0 ELSE 1 END AS `nomatch` 83 | FROM `history` 84 | WHERE `instance` = :instance 85 | AND `type` = :type 86 | AND `timestamp` BETWEEN :timeStart AND :timeEnd 87 | ) AS `match_table`" 88 | ); 89 | 90 | $query->bindParam(':instance', $instance); 91 | $query->bindParam(':type', $type); 92 | $query->bindParam(':value', $value); 93 | $query->bindParam(':timeStart', $timeStart); 94 | $query->bindParam(':timeEnd', $timeEnd); 95 | 96 | $query->execute(); 97 | 98 | $result = $query->fetchObject(); 99 | 100 | if (!is_object($result)) { 101 | $error = $query->errorInfo(); 102 | throw new \Exception(print_r($error[2], true)); 103 | } 104 | 105 | return $result->match > 0 && $result->nomatch == 0; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/instance-api/lib/IsacApiConnector.class.php: -------------------------------------------------------------------------------- 1 | curl = new \Curl\Curl(); 27 | } 28 | 29 | /** 30 | * Authenticates against the ISAC API 31 | * 32 | * @return bool Success 33 | */ 34 | public function authenticate(){ 35 | 36 | $loginEndPoint = APIURL . LOGINPATH; 37 | 38 | $this->curl->post($loginEndPoint, array( 39 | 'grant_type' => 'client_credentials', 40 | 'client_id' => ISACUSERNAME, 41 | 'client_secret' => ISACPASSWORD, 42 | 'devKey' => DEVKEY, 43 | 'appKey' => APPKEY, 44 | )); 45 | 46 | if ($this->curl->error) { 47 | return FALSE; 48 | } 49 | $loginRespone = $this->curl->response; 50 | 51 | if($loginRespone == null){ 52 | return FALSE; 53 | } 54 | $this->token = $loginRespone->access_token; 55 | $responeCookies = $this->curl->responseCookies; 56 | 57 | foreach($responeCookies as $responeCookieName => $responeCookieValue){ 58 | $cookie = new stdClass(); 59 | $cookie->name = $responeCookieName; 60 | $cookie->value = $responeCookieValue; 61 | $this->cookies[] = $cookie; 62 | } 63 | } 64 | 65 | /** 66 | * Finds an instance by ip address 67 | * 68 | * @param string $ip ip of the searched instance 69 | * 70 | * @return null or instance 71 | */ 72 | public function findInstanceByIP(string $ip){ 73 | 74 | $instances = $this->getInstances(); 75 | 76 | $foundInstance = null; 77 | foreach($instances as $instance) { 78 | 79 | if (strcasecmp($instance->ip_address, $ip) == 0) { 80 | $foundInstance = $instance; 81 | } 82 | } 83 | return $foundInstance; 84 | } 85 | 86 | /** 87 | * Retrieves all instances 88 | * 89 | * @return bool|instance array 90 | */ 91 | public function getInstances() 92 | { 93 | $instanceEndPoint = APIURL . INSTANCEPATH; 94 | $this->addAuthentication(); 95 | $this->curl->get($instanceEndPoint, array()); 96 | 97 | if ($this->curl->error) { 98 | return FALSE; 99 | } 100 | $instances = $this->curl->response; 101 | 102 | if ($instances == null) { 103 | return FALSE; 104 | } 105 | 106 | return $instances; 107 | 108 | } 109 | 110 | /** 111 | * Adds the authentication to the curl request 112 | */ 113 | public function addAuthentication(){ 114 | 115 | // adding the cookies 116 | foreach($this->cookies as $cookie){ 117 | $this->curl->setCookie($cookie->name, $cookie->value); 118 | } 119 | 120 | // adding the authentication header 121 | $this->curl->setHeader("authorization", "bearer " . $this->token ); 122 | } 123 | 124 | /** 125 | * Triggers the instance resize 126 | * 127 | * @param $instance instance object with the new parameter (cpu/ram/storage) 128 | * 129 | * @return bool|null resize result/resized parameter 130 | */ 131 | public function resizeInstance($instance){ 132 | 133 | $instanceResizeEndPoint = APIURL . INSTANCERESIZEPATH . "/" . $instance->instance_id; 134 | 135 | $this->addAuthentication(); 136 | $this->curl->put($instanceResizeEndPoint, array("cpu" => $instance->cpu, "ram" => $instance->ram, "storage" => $instance->storage)); 137 | 138 | if ($this->curl->error) { 139 | return FALSE; 140 | } 141 | 142 | $resizeResult = $this->curl->response; 143 | 144 | if ($resizeResult == null) { 145 | return FALSE; 146 | } 147 | 148 | return $resizeResult; 149 | } 150 | } -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "738b730d460ff2217c361f9bfda71762", 8 | "content-hash": "b06995c242bfe55e9594c3ecdc9adf42", 9 | "packages": [ 10 | { 11 | "name": "container-interop/container-interop", 12 | "version": "1.2.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/container-interop/container-interop.git", 16 | "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", 21 | "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "psr/container": "^1.0" 26 | }, 27 | "type": "library", 28 | "autoload": { 29 | "psr-4": { 30 | "Interop\\Container\\": "src/Interop/Container/" 31 | } 32 | }, 33 | "notification-url": "https://packagist.org/downloads/", 34 | "license": [ 35 | "MIT" 36 | ], 37 | "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", 38 | "homepage": "https://github.com/container-interop/container-interop", 39 | "time": "2017-02-14 19:40:03" 40 | }, 41 | { 42 | "name": "nikic/fast-route", 43 | "version": "v1.2.0", 44 | "source": { 45 | "type": "git", 46 | "url": "https://github.com/nikic/FastRoute.git", 47 | "reference": "b5f95749071c82a8e0f58586987627054400cdf6" 48 | }, 49 | "dist": { 50 | "type": "zip", 51 | "url": "https://api.github.com/repos/nikic/FastRoute/zipball/b5f95749071c82a8e0f58586987627054400cdf6", 52 | "reference": "b5f95749071c82a8e0f58586987627054400cdf6", 53 | "shasum": "" 54 | }, 55 | "require": { 56 | "php": ">=5.4.0" 57 | }, 58 | "type": "library", 59 | "autoload": { 60 | "psr-4": { 61 | "FastRoute\\": "src/" 62 | }, 63 | "files": [ 64 | "src/functions.php" 65 | ] 66 | }, 67 | "notification-url": "https://packagist.org/downloads/", 68 | "license": [ 69 | "BSD-3-Clause" 70 | ], 71 | "authors": [ 72 | { 73 | "name": "Nikita Popov", 74 | "email": "nikic@php.net" 75 | } 76 | ], 77 | "description": "Fast request router for PHP", 78 | "keywords": [ 79 | "router", 80 | "routing" 81 | ], 82 | "time": "2017-01-19 11:35:12" 83 | }, 84 | { 85 | "name": "pimple/pimple", 86 | "version": "v3.0.2", 87 | "source": { 88 | "type": "git", 89 | "url": "https://github.com/silexphp/Pimple.git", 90 | "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a" 91 | }, 92 | "dist": { 93 | "type": "zip", 94 | "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a", 95 | "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a", 96 | "shasum": "" 97 | }, 98 | "require": { 99 | "php": ">=5.3.0" 100 | }, 101 | "type": "library", 102 | "extra": { 103 | "branch-alias": { 104 | "dev-master": "3.0.x-dev" 105 | } 106 | }, 107 | "autoload": { 108 | "psr-0": { 109 | "Pimple": "src/" 110 | } 111 | }, 112 | "notification-url": "https://packagist.org/downloads/", 113 | "license": [ 114 | "MIT" 115 | ], 116 | "authors": [ 117 | { 118 | "name": "Fabien Potencier", 119 | "email": "fabien@symfony.com" 120 | } 121 | ], 122 | "description": "Pimple, a simple Dependency Injection Container", 123 | "homepage": "http://pimple.sensiolabs.org", 124 | "keywords": [ 125 | "container", 126 | "dependency injection" 127 | ], 128 | "time": "2015-09-11 15:10:35" 129 | }, 130 | { 131 | "name": "psr/container", 132 | "version": "1.0.0", 133 | "source": { 134 | "type": "git", 135 | "url": "https://github.com/php-fig/container.git", 136 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" 137 | }, 138 | "dist": { 139 | "type": "zip", 140 | "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 141 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 142 | "shasum": "" 143 | }, 144 | "require": { 145 | "php": ">=5.3.0" 146 | }, 147 | "type": "library", 148 | "extra": { 149 | "branch-alias": { 150 | "dev-master": "1.0.x-dev" 151 | } 152 | }, 153 | "autoload": { 154 | "psr-4": { 155 | "Psr\\Container\\": "src/" 156 | } 157 | }, 158 | "notification-url": "https://packagist.org/downloads/", 159 | "license": [ 160 | "MIT" 161 | ], 162 | "authors": [ 163 | { 164 | "name": "PHP-FIG", 165 | "homepage": "http://www.php-fig.org/" 166 | } 167 | ], 168 | "description": "Common Container Interface (PHP FIG PSR-11)", 169 | "homepage": "https://github.com/php-fig/container", 170 | "keywords": [ 171 | "PSR-11", 172 | "container", 173 | "container-interface", 174 | "container-interop", 175 | "psr" 176 | ], 177 | "time": "2017-02-14 16:28:37" 178 | }, 179 | { 180 | "name": "psr/http-message", 181 | "version": "1.0.1", 182 | "source": { 183 | "type": "git", 184 | "url": "https://github.com/php-fig/http-message.git", 185 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" 186 | }, 187 | "dist": { 188 | "type": "zip", 189 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", 190 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", 191 | "shasum": "" 192 | }, 193 | "require": { 194 | "php": ">=5.3.0" 195 | }, 196 | "type": "library", 197 | "extra": { 198 | "branch-alias": { 199 | "dev-master": "1.0.x-dev" 200 | } 201 | }, 202 | "autoload": { 203 | "psr-4": { 204 | "Psr\\Http\\Message\\": "src/" 205 | } 206 | }, 207 | "notification-url": "https://packagist.org/downloads/", 208 | "license": [ 209 | "MIT" 210 | ], 211 | "authors": [ 212 | { 213 | "name": "PHP-FIG", 214 | "homepage": "http://www.php-fig.org/" 215 | } 216 | ], 217 | "description": "Common interface for HTTP messages", 218 | "homepage": "https://github.com/php-fig/http-message", 219 | "keywords": [ 220 | "http", 221 | "http-message", 222 | "psr", 223 | "psr-7", 224 | "request", 225 | "response" 226 | ], 227 | "time": "2016-08-06 14:39:51" 228 | }, 229 | { 230 | "name": "slim/slim", 231 | "version": "3.8.1", 232 | "source": { 233 | "type": "git", 234 | "url": "https://github.com/slimphp/Slim.git", 235 | "reference": "5385302707530b2bccee1769613ad769859b826d" 236 | }, 237 | "dist": { 238 | "type": "zip", 239 | "url": "https://api.github.com/repos/slimphp/Slim/zipball/5385302707530b2bccee1769613ad769859b826d", 240 | "reference": "5385302707530b2bccee1769613ad769859b826d", 241 | "shasum": "" 242 | }, 243 | "require": { 244 | "container-interop/container-interop": "^1.2", 245 | "nikic/fast-route": "^1.0", 246 | "php": ">=5.5.0", 247 | "pimple/pimple": "^3.0", 248 | "psr/container": "^1.0", 249 | "psr/http-message": "^1.0" 250 | }, 251 | "provide": { 252 | "psr/http-message-implementation": "1.0" 253 | }, 254 | "require-dev": { 255 | "phpunit/phpunit": "^4.0", 256 | "squizlabs/php_codesniffer": "^2.5" 257 | }, 258 | "type": "library", 259 | "autoload": { 260 | "psr-4": { 261 | "Slim\\": "Slim" 262 | } 263 | }, 264 | "notification-url": "https://packagist.org/downloads/", 265 | "license": [ 266 | "MIT" 267 | ], 268 | "authors": [ 269 | { 270 | "name": "Rob Allen", 271 | "email": "rob@akrabat.com", 272 | "homepage": "http://akrabat.com" 273 | }, 274 | { 275 | "name": "Josh Lockhart", 276 | "email": "hello@joshlockhart.com", 277 | "homepage": "https://joshlockhart.com" 278 | }, 279 | { 280 | "name": "Gabriel Manricks", 281 | "email": "gmanricks@me.com", 282 | "homepage": "http://gabrielmanricks.com" 283 | }, 284 | { 285 | "name": "Andrew Smith", 286 | "email": "a.smith@silentworks.co.uk", 287 | "homepage": "http://silentworks.co.uk" 288 | } 289 | ], 290 | "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", 291 | "homepage": "https://slimframework.com", 292 | "keywords": [ 293 | "api", 294 | "framework", 295 | "micro", 296 | "router" 297 | ], 298 | "time": "2017-03-19 17:55:20" 299 | } 300 | ], 301 | "packages-dev": [ 302 | { 303 | "name": "doctrine/instantiator", 304 | "version": "1.0.5", 305 | "source": { 306 | "type": "git", 307 | "url": "https://github.com/doctrine/instantiator.git", 308 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" 309 | }, 310 | "dist": { 311 | "type": "zip", 312 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", 313 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", 314 | "shasum": "" 315 | }, 316 | "require": { 317 | "php": ">=5.3,<8.0-DEV" 318 | }, 319 | "require-dev": { 320 | "athletic/athletic": "~0.1.8", 321 | "ext-pdo": "*", 322 | "ext-phar": "*", 323 | "phpunit/phpunit": "~4.0", 324 | "squizlabs/php_codesniffer": "~2.0" 325 | }, 326 | "type": "library", 327 | "extra": { 328 | "branch-alias": { 329 | "dev-master": "1.0.x-dev" 330 | } 331 | }, 332 | "autoload": { 333 | "psr-4": { 334 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 335 | } 336 | }, 337 | "notification-url": "https://packagist.org/downloads/", 338 | "license": [ 339 | "MIT" 340 | ], 341 | "authors": [ 342 | { 343 | "name": "Marco Pivetta", 344 | "email": "ocramius@gmail.com", 345 | "homepage": "http://ocramius.github.com/" 346 | } 347 | ], 348 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 349 | "homepage": "https://github.com/doctrine/instantiator", 350 | "keywords": [ 351 | "constructor", 352 | "instantiate" 353 | ], 354 | "time": "2015-06-14 21:17:01" 355 | }, 356 | { 357 | "name": "myclabs/deep-copy", 358 | "version": "1.6.0", 359 | "source": { 360 | "type": "git", 361 | "url": "https://github.com/myclabs/DeepCopy.git", 362 | "reference": "5a5a9fc8025a08d8919be87d6884d5a92520cefe" 363 | }, 364 | "dist": { 365 | "type": "zip", 366 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/5a5a9fc8025a08d8919be87d6884d5a92520cefe", 367 | "reference": "5a5a9fc8025a08d8919be87d6884d5a92520cefe", 368 | "shasum": "" 369 | }, 370 | "require": { 371 | "php": ">=5.4.0" 372 | }, 373 | "require-dev": { 374 | "doctrine/collections": "1.*", 375 | "phpunit/phpunit": "~4.1" 376 | }, 377 | "type": "library", 378 | "autoload": { 379 | "psr-4": { 380 | "DeepCopy\\": "src/DeepCopy/" 381 | } 382 | }, 383 | "notification-url": "https://packagist.org/downloads/", 384 | "license": [ 385 | "MIT" 386 | ], 387 | "description": "Create deep copies (clones) of your objects", 388 | "homepage": "https://github.com/myclabs/DeepCopy", 389 | "keywords": [ 390 | "clone", 391 | "copy", 392 | "duplicate", 393 | "object", 394 | "object graph" 395 | ], 396 | "time": "2017-01-26 22:05:40" 397 | }, 398 | { 399 | "name": "phpdocumentor/reflection-common", 400 | "version": "1.0", 401 | "source": { 402 | "type": "git", 403 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 404 | "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" 405 | }, 406 | "dist": { 407 | "type": "zip", 408 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", 409 | "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", 410 | "shasum": "" 411 | }, 412 | "require": { 413 | "php": ">=5.5" 414 | }, 415 | "require-dev": { 416 | "phpunit/phpunit": "^4.6" 417 | }, 418 | "type": "library", 419 | "extra": { 420 | "branch-alias": { 421 | "dev-master": "1.0.x-dev" 422 | } 423 | }, 424 | "autoload": { 425 | "psr-4": { 426 | "phpDocumentor\\Reflection\\": [ 427 | "src" 428 | ] 429 | } 430 | }, 431 | "notification-url": "https://packagist.org/downloads/", 432 | "license": [ 433 | "MIT" 434 | ], 435 | "authors": [ 436 | { 437 | "name": "Jaap van Otterdijk", 438 | "email": "opensource@ijaap.nl" 439 | } 440 | ], 441 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 442 | "homepage": "http://www.phpdoc.org", 443 | "keywords": [ 444 | "FQSEN", 445 | "phpDocumentor", 446 | "phpdoc", 447 | "reflection", 448 | "static analysis" 449 | ], 450 | "time": "2015-12-27 11:43:31" 451 | }, 452 | { 453 | "name": "phpdocumentor/reflection-docblock", 454 | "version": "3.1.1", 455 | "source": { 456 | "type": "git", 457 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 458 | "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" 459 | }, 460 | "dist": { 461 | "type": "zip", 462 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", 463 | "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", 464 | "shasum": "" 465 | }, 466 | "require": { 467 | "php": ">=5.5", 468 | "phpdocumentor/reflection-common": "^1.0@dev", 469 | "phpdocumentor/type-resolver": "^0.2.0", 470 | "webmozart/assert": "^1.0" 471 | }, 472 | "require-dev": { 473 | "mockery/mockery": "^0.9.4", 474 | "phpunit/phpunit": "^4.4" 475 | }, 476 | "type": "library", 477 | "autoload": { 478 | "psr-4": { 479 | "phpDocumentor\\Reflection\\": [ 480 | "src/" 481 | ] 482 | } 483 | }, 484 | "notification-url": "https://packagist.org/downloads/", 485 | "license": [ 486 | "MIT" 487 | ], 488 | "authors": [ 489 | { 490 | "name": "Mike van Riel", 491 | "email": "me@mikevanriel.com" 492 | } 493 | ], 494 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 495 | "time": "2016-09-30 07:12:33" 496 | }, 497 | { 498 | "name": "phpdocumentor/type-resolver", 499 | "version": "0.2.1", 500 | "source": { 501 | "type": "git", 502 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 503 | "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" 504 | }, 505 | "dist": { 506 | "type": "zip", 507 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", 508 | "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", 509 | "shasum": "" 510 | }, 511 | "require": { 512 | "php": ">=5.5", 513 | "phpdocumentor/reflection-common": "^1.0" 514 | }, 515 | "require-dev": { 516 | "mockery/mockery": "^0.9.4", 517 | "phpunit/phpunit": "^5.2||^4.8.24" 518 | }, 519 | "type": "library", 520 | "extra": { 521 | "branch-alias": { 522 | "dev-master": "1.0.x-dev" 523 | } 524 | }, 525 | "autoload": { 526 | "psr-4": { 527 | "phpDocumentor\\Reflection\\": [ 528 | "src/" 529 | ] 530 | } 531 | }, 532 | "notification-url": "https://packagist.org/downloads/", 533 | "license": [ 534 | "MIT" 535 | ], 536 | "authors": [ 537 | { 538 | "name": "Mike van Riel", 539 | "email": "me@mikevanriel.com" 540 | } 541 | ], 542 | "time": "2016-11-25 06:54:22" 543 | }, 544 | { 545 | "name": "phpspec/prophecy", 546 | "version": "v1.7.0", 547 | "source": { 548 | "type": "git", 549 | "url": "https://github.com/phpspec/prophecy.git", 550 | "reference": "93d39f1f7f9326d746203c7c056f300f7f126073" 551 | }, 552 | "dist": { 553 | "type": "zip", 554 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073", 555 | "reference": "93d39f1f7f9326d746203c7c056f300f7f126073", 556 | "shasum": "" 557 | }, 558 | "require": { 559 | "doctrine/instantiator": "^1.0.2", 560 | "php": "^5.3|^7.0", 561 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", 562 | "sebastian/comparator": "^1.1|^2.0", 563 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" 564 | }, 565 | "require-dev": { 566 | "phpspec/phpspec": "^2.5|^3.2", 567 | "phpunit/phpunit": "^4.8 || ^5.6.5" 568 | }, 569 | "type": "library", 570 | "extra": { 571 | "branch-alias": { 572 | "dev-master": "1.6.x-dev" 573 | } 574 | }, 575 | "autoload": { 576 | "psr-0": { 577 | "Prophecy\\": "src/" 578 | } 579 | }, 580 | "notification-url": "https://packagist.org/downloads/", 581 | "license": [ 582 | "MIT" 583 | ], 584 | "authors": [ 585 | { 586 | "name": "Konstantin Kudryashov", 587 | "email": "ever.zet@gmail.com", 588 | "homepage": "http://everzet.com" 589 | }, 590 | { 591 | "name": "Marcello Duarte", 592 | "email": "marcello.duarte@gmail.com" 593 | } 594 | ], 595 | "description": "Highly opinionated mocking framework for PHP 5.3+", 596 | "homepage": "https://github.com/phpspec/prophecy", 597 | "keywords": [ 598 | "Double", 599 | "Dummy", 600 | "fake", 601 | "mock", 602 | "spy", 603 | "stub" 604 | ], 605 | "time": "2017-03-02 20:05:34" 606 | }, 607 | { 608 | "name": "phpunit/dbunit", 609 | "version": "3.0.0", 610 | "source": { 611 | "type": "git", 612 | "url": "https://github.com/sebastianbergmann/dbunit.git", 613 | "reference": "f2f8bec1d6ad7ad0bcdb47c1ed56d9d42d3e39ab" 614 | }, 615 | "dist": { 616 | "type": "zip", 617 | "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/f2f8bec1d6ad7ad0bcdb47c1ed56d9d42d3e39ab", 618 | "reference": "f2f8bec1d6ad7ad0bcdb47c1ed56d9d42d3e39ab", 619 | "shasum": "" 620 | }, 621 | "require": { 622 | "ext-pdo": "*", 623 | "ext-simplexml": "*", 624 | "php": "^7.0", 625 | "phpunit/phpunit": "^6.0", 626 | "symfony/yaml": "^3.0" 627 | }, 628 | "type": "library", 629 | "extra": { 630 | "branch-alias": { 631 | "dev-master": "3.0.x-dev" 632 | } 633 | }, 634 | "autoload": { 635 | "classmap": [ 636 | "src/" 637 | ] 638 | }, 639 | "notification-url": "https://packagist.org/downloads/", 640 | "license": [ 641 | "BSD-3-Clause" 642 | ], 643 | "authors": [ 644 | { 645 | "name": "Sebastian Bergmann", 646 | "email": "sebastian@phpunit.de", 647 | "role": "lead" 648 | } 649 | ], 650 | "description": "PHPUnit extension for database interaction testing", 651 | "homepage": "https://github.com/sebastianbergmann/dbunit/", 652 | "keywords": [ 653 | "database", 654 | "testing", 655 | "xunit" 656 | ], 657 | "time": "2017-02-03 08:50:36" 658 | }, 659 | { 660 | "name": "phpunit/php-code-coverage", 661 | "version": "5.0.3", 662 | "source": { 663 | "type": "git", 664 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 665 | "reference": "4e99e1c4f9b05cbf4d6e84b100b3ff4107cf8cd1" 666 | }, 667 | "dist": { 668 | "type": "zip", 669 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4e99e1c4f9b05cbf4d6e84b100b3ff4107cf8cd1", 670 | "reference": "4e99e1c4f9b05cbf4d6e84b100b3ff4107cf8cd1", 671 | "shasum": "" 672 | }, 673 | "require": { 674 | "ext-dom": "*", 675 | "ext-xmlwriter": "*", 676 | "php": "^7.0", 677 | "phpunit/php-file-iterator": "^1.3", 678 | "phpunit/php-text-template": "^1.2", 679 | "phpunit/php-token-stream": "^1.4.11 || ^2.0", 680 | "sebastian/code-unit-reverse-lookup": "^1.0", 681 | "sebastian/environment": "^2.0", 682 | "sebastian/version": "^2.0" 683 | }, 684 | "require-dev": { 685 | "ext-xdebug": "^2.5", 686 | "phpunit/phpunit": "^6.0" 687 | }, 688 | "suggest": { 689 | "ext-xdebug": "^2.5.1" 690 | }, 691 | "type": "library", 692 | "extra": { 693 | "branch-alias": { 694 | "dev-master": "5.0.x-dev" 695 | } 696 | }, 697 | "autoload": { 698 | "classmap": [ 699 | "src/" 700 | ] 701 | }, 702 | "notification-url": "https://packagist.org/downloads/", 703 | "license": [ 704 | "BSD-3-Clause" 705 | ], 706 | "authors": [ 707 | { 708 | "name": "Sebastian Bergmann", 709 | "email": "sb@sebastian-bergmann.de", 710 | "role": "lead" 711 | } 712 | ], 713 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 714 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 715 | "keywords": [ 716 | "coverage", 717 | "testing", 718 | "xunit" 719 | ], 720 | "time": "2017-03-06 14:22:16" 721 | }, 722 | { 723 | "name": "phpunit/php-file-iterator", 724 | "version": "1.4.2", 725 | "source": { 726 | "type": "git", 727 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 728 | "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" 729 | }, 730 | "dist": { 731 | "type": "zip", 732 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", 733 | "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", 734 | "shasum": "" 735 | }, 736 | "require": { 737 | "php": ">=5.3.3" 738 | }, 739 | "type": "library", 740 | "extra": { 741 | "branch-alias": { 742 | "dev-master": "1.4.x-dev" 743 | } 744 | }, 745 | "autoload": { 746 | "classmap": [ 747 | "src/" 748 | ] 749 | }, 750 | "notification-url": "https://packagist.org/downloads/", 751 | "license": [ 752 | "BSD-3-Clause" 753 | ], 754 | "authors": [ 755 | { 756 | "name": "Sebastian Bergmann", 757 | "email": "sb@sebastian-bergmann.de", 758 | "role": "lead" 759 | } 760 | ], 761 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 762 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 763 | "keywords": [ 764 | "filesystem", 765 | "iterator" 766 | ], 767 | "time": "2016-10-03 07:40:28" 768 | }, 769 | { 770 | "name": "phpunit/php-text-template", 771 | "version": "1.2.1", 772 | "source": { 773 | "type": "git", 774 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 775 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 776 | }, 777 | "dist": { 778 | "type": "zip", 779 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 780 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 781 | "shasum": "" 782 | }, 783 | "require": { 784 | "php": ">=5.3.3" 785 | }, 786 | "type": "library", 787 | "autoload": { 788 | "classmap": [ 789 | "src/" 790 | ] 791 | }, 792 | "notification-url": "https://packagist.org/downloads/", 793 | "license": [ 794 | "BSD-3-Clause" 795 | ], 796 | "authors": [ 797 | { 798 | "name": "Sebastian Bergmann", 799 | "email": "sebastian@phpunit.de", 800 | "role": "lead" 801 | } 802 | ], 803 | "description": "Simple template engine.", 804 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 805 | "keywords": [ 806 | "template" 807 | ], 808 | "time": "2015-06-21 13:50:34" 809 | }, 810 | { 811 | "name": "phpunit/php-timer", 812 | "version": "1.0.9", 813 | "source": { 814 | "type": "git", 815 | "url": "https://github.com/sebastianbergmann/php-timer.git", 816 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" 817 | }, 818 | "dist": { 819 | "type": "zip", 820 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 821 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 822 | "shasum": "" 823 | }, 824 | "require": { 825 | "php": "^5.3.3 || ^7.0" 826 | }, 827 | "require-dev": { 828 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 829 | }, 830 | "type": "library", 831 | "extra": { 832 | "branch-alias": { 833 | "dev-master": "1.0-dev" 834 | } 835 | }, 836 | "autoload": { 837 | "classmap": [ 838 | "src/" 839 | ] 840 | }, 841 | "notification-url": "https://packagist.org/downloads/", 842 | "license": [ 843 | "BSD-3-Clause" 844 | ], 845 | "authors": [ 846 | { 847 | "name": "Sebastian Bergmann", 848 | "email": "sb@sebastian-bergmann.de", 849 | "role": "lead" 850 | } 851 | ], 852 | "description": "Utility class for timing", 853 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 854 | "keywords": [ 855 | "timer" 856 | ], 857 | "time": "2017-02-26 11:10:40" 858 | }, 859 | { 860 | "name": "phpunit/php-token-stream", 861 | "version": "1.4.11", 862 | "source": { 863 | "type": "git", 864 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 865 | "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" 866 | }, 867 | "dist": { 868 | "type": "zip", 869 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", 870 | "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", 871 | "shasum": "" 872 | }, 873 | "require": { 874 | "ext-tokenizer": "*", 875 | "php": ">=5.3.3" 876 | }, 877 | "require-dev": { 878 | "phpunit/phpunit": "~4.2" 879 | }, 880 | "type": "library", 881 | "extra": { 882 | "branch-alias": { 883 | "dev-master": "1.4-dev" 884 | } 885 | }, 886 | "autoload": { 887 | "classmap": [ 888 | "src/" 889 | ] 890 | }, 891 | "notification-url": "https://packagist.org/downloads/", 892 | "license": [ 893 | "BSD-3-Clause" 894 | ], 895 | "authors": [ 896 | { 897 | "name": "Sebastian Bergmann", 898 | "email": "sebastian@phpunit.de" 899 | } 900 | ], 901 | "description": "Wrapper around PHP's tokenizer extension.", 902 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 903 | "keywords": [ 904 | "tokenizer" 905 | ], 906 | "time": "2017-02-27 10:12:30" 907 | }, 908 | { 909 | "name": "phpunit/phpunit", 910 | "version": "6.0.10", 911 | "source": { 912 | "type": "git", 913 | "url": "https://github.com/sebastianbergmann/phpunit.git", 914 | "reference": "8a536f409ebae632b92b7e7288e068248fe365ed" 915 | }, 916 | "dist": { 917 | "type": "zip", 918 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8a536f409ebae632b92b7e7288e068248fe365ed", 919 | "reference": "8a536f409ebae632b92b7e7288e068248fe365ed", 920 | "shasum": "" 921 | }, 922 | "require": { 923 | "ext-dom": "*", 924 | "ext-json": "*", 925 | "ext-libxml": "*", 926 | "ext-mbstring": "*", 927 | "ext-xml": "*", 928 | "myclabs/deep-copy": "^1.3", 929 | "php": "^7.0", 930 | "phpspec/prophecy": "^1.7", 931 | "phpunit/php-code-coverage": "^5.0", 932 | "phpunit/php-file-iterator": "^1.4", 933 | "phpunit/php-text-template": "^1.2", 934 | "phpunit/php-timer": "^1.0.6", 935 | "phpunit/phpunit-mock-objects": "^4.0", 936 | "sebastian/comparator": "^2.0", 937 | "sebastian/diff": "^1.2", 938 | "sebastian/environment": "^2.0", 939 | "sebastian/exporter": "^3.0", 940 | "sebastian/global-state": "^1.1 || ^2.0", 941 | "sebastian/object-enumerator": "^3.0.2", 942 | "sebastian/resource-operations": "^1.0", 943 | "sebastian/version": "^2.0" 944 | }, 945 | "conflict": { 946 | "phpdocumentor/reflection-docblock": "3.0.2", 947 | "phpunit/dbunit": "<3.0" 948 | }, 949 | "require-dev": { 950 | "ext-pdo": "*" 951 | }, 952 | "suggest": { 953 | "ext-xdebug": "*", 954 | "phpunit/php-invoker": "^1.1" 955 | }, 956 | "bin": [ 957 | "phpunit" 958 | ], 959 | "type": "library", 960 | "extra": { 961 | "branch-alias": { 962 | "dev-master": "6.0.x-dev" 963 | } 964 | }, 965 | "autoload": { 966 | "classmap": [ 967 | "src/" 968 | ] 969 | }, 970 | "notification-url": "https://packagist.org/downloads/", 971 | "license": [ 972 | "BSD-3-Clause" 973 | ], 974 | "authors": [ 975 | { 976 | "name": "Sebastian Bergmann", 977 | "email": "sebastian@phpunit.de", 978 | "role": "lead" 979 | } 980 | ], 981 | "description": "The PHP Unit Testing framework.", 982 | "homepage": "https://phpunit.de/", 983 | "keywords": [ 984 | "phpunit", 985 | "testing", 986 | "xunit" 987 | ], 988 | "time": "2017-03-19 16:54:28" 989 | }, 990 | { 991 | "name": "phpunit/phpunit-mock-objects", 992 | "version": "4.0.1", 993 | "source": { 994 | "type": "git", 995 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 996 | "reference": "eabce450df194817a7d7e27e19013569a903a2bf" 997 | }, 998 | "dist": { 999 | "type": "zip", 1000 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/eabce450df194817a7d7e27e19013569a903a2bf", 1001 | "reference": "eabce450df194817a7d7e27e19013569a903a2bf", 1002 | "shasum": "" 1003 | }, 1004 | "require": { 1005 | "doctrine/instantiator": "^1.0.2", 1006 | "php": "^7.0", 1007 | "phpunit/php-text-template": "^1.2", 1008 | "sebastian/exporter": "^3.0" 1009 | }, 1010 | "conflict": { 1011 | "phpunit/phpunit": "<6.0" 1012 | }, 1013 | "require-dev": { 1014 | "phpunit/phpunit": "^6.0" 1015 | }, 1016 | "suggest": { 1017 | "ext-soap": "*" 1018 | }, 1019 | "type": "library", 1020 | "extra": { 1021 | "branch-alias": { 1022 | "dev-master": "4.0.x-dev" 1023 | } 1024 | }, 1025 | "autoload": { 1026 | "classmap": [ 1027 | "src/" 1028 | ] 1029 | }, 1030 | "notification-url": "https://packagist.org/downloads/", 1031 | "license": [ 1032 | "BSD-3-Clause" 1033 | ], 1034 | "authors": [ 1035 | { 1036 | "name": "Sebastian Bergmann", 1037 | "email": "sb@sebastian-bergmann.de", 1038 | "role": "lead" 1039 | } 1040 | ], 1041 | "description": "Mock Object library for PHPUnit", 1042 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 1043 | "keywords": [ 1044 | "mock", 1045 | "xunit" 1046 | ], 1047 | "time": "2017-03-03 06:30:20" 1048 | }, 1049 | { 1050 | "name": "sebastian/code-unit-reverse-lookup", 1051 | "version": "1.0.1", 1052 | "source": { 1053 | "type": "git", 1054 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 1055 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" 1056 | }, 1057 | "dist": { 1058 | "type": "zip", 1059 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 1060 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 1061 | "shasum": "" 1062 | }, 1063 | "require": { 1064 | "php": "^5.6 || ^7.0" 1065 | }, 1066 | "require-dev": { 1067 | "phpunit/phpunit": "^5.7 || ^6.0" 1068 | }, 1069 | "type": "library", 1070 | "extra": { 1071 | "branch-alias": { 1072 | "dev-master": "1.0.x-dev" 1073 | } 1074 | }, 1075 | "autoload": { 1076 | "classmap": [ 1077 | "src/" 1078 | ] 1079 | }, 1080 | "notification-url": "https://packagist.org/downloads/", 1081 | "license": [ 1082 | "BSD-3-Clause" 1083 | ], 1084 | "authors": [ 1085 | { 1086 | "name": "Sebastian Bergmann", 1087 | "email": "sebastian@phpunit.de" 1088 | } 1089 | ], 1090 | "description": "Looks up which function or method a line of code belongs to", 1091 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 1092 | "time": "2017-03-04 06:30:41" 1093 | }, 1094 | { 1095 | "name": "sebastian/comparator", 1096 | "version": "2.0.0", 1097 | "source": { 1098 | "type": "git", 1099 | "url": "https://github.com/sebastianbergmann/comparator.git", 1100 | "reference": "20f84f468cb67efee293246e6a09619b891f55f0" 1101 | }, 1102 | "dist": { 1103 | "type": "zip", 1104 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/20f84f468cb67efee293246e6a09619b891f55f0", 1105 | "reference": "20f84f468cb67efee293246e6a09619b891f55f0", 1106 | "shasum": "" 1107 | }, 1108 | "require": { 1109 | "php": "^7.0", 1110 | "sebastian/diff": "^1.2", 1111 | "sebastian/exporter": "^3.0" 1112 | }, 1113 | "require-dev": { 1114 | "phpunit/phpunit": "^6.0" 1115 | }, 1116 | "type": "library", 1117 | "extra": { 1118 | "branch-alias": { 1119 | "dev-master": "2.0.x-dev" 1120 | } 1121 | }, 1122 | "autoload": { 1123 | "classmap": [ 1124 | "src/" 1125 | ] 1126 | }, 1127 | "notification-url": "https://packagist.org/downloads/", 1128 | "license": [ 1129 | "BSD-3-Clause" 1130 | ], 1131 | "authors": [ 1132 | { 1133 | "name": "Jeff Welch", 1134 | "email": "whatthejeff@gmail.com" 1135 | }, 1136 | { 1137 | "name": "Volker Dusch", 1138 | "email": "github@wallbash.com" 1139 | }, 1140 | { 1141 | "name": "Bernhard Schussek", 1142 | "email": "bschussek@2bepublished.at" 1143 | }, 1144 | { 1145 | "name": "Sebastian Bergmann", 1146 | "email": "sebastian@phpunit.de" 1147 | } 1148 | ], 1149 | "description": "Provides the functionality to compare PHP values for equality", 1150 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 1151 | "keywords": [ 1152 | "comparator", 1153 | "compare", 1154 | "equality" 1155 | ], 1156 | "time": "2017-03-03 06:26:08" 1157 | }, 1158 | { 1159 | "name": "sebastian/diff", 1160 | "version": "1.4.1", 1161 | "source": { 1162 | "type": "git", 1163 | "url": "https://github.com/sebastianbergmann/diff.git", 1164 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" 1165 | }, 1166 | "dist": { 1167 | "type": "zip", 1168 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", 1169 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", 1170 | "shasum": "" 1171 | }, 1172 | "require": { 1173 | "php": ">=5.3.3" 1174 | }, 1175 | "require-dev": { 1176 | "phpunit/phpunit": "~4.8" 1177 | }, 1178 | "type": "library", 1179 | "extra": { 1180 | "branch-alias": { 1181 | "dev-master": "1.4-dev" 1182 | } 1183 | }, 1184 | "autoload": { 1185 | "classmap": [ 1186 | "src/" 1187 | ] 1188 | }, 1189 | "notification-url": "https://packagist.org/downloads/", 1190 | "license": [ 1191 | "BSD-3-Clause" 1192 | ], 1193 | "authors": [ 1194 | { 1195 | "name": "Kore Nordmann", 1196 | "email": "mail@kore-nordmann.de" 1197 | }, 1198 | { 1199 | "name": "Sebastian Bergmann", 1200 | "email": "sebastian@phpunit.de" 1201 | } 1202 | ], 1203 | "description": "Diff implementation", 1204 | "homepage": "https://github.com/sebastianbergmann/diff", 1205 | "keywords": [ 1206 | "diff" 1207 | ], 1208 | "time": "2015-12-08 07:14:41" 1209 | }, 1210 | { 1211 | "name": "sebastian/environment", 1212 | "version": "2.0.0", 1213 | "source": { 1214 | "type": "git", 1215 | "url": "https://github.com/sebastianbergmann/environment.git", 1216 | "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" 1217 | }, 1218 | "dist": { 1219 | "type": "zip", 1220 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", 1221 | "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", 1222 | "shasum": "" 1223 | }, 1224 | "require": { 1225 | "php": "^5.6 || ^7.0" 1226 | }, 1227 | "require-dev": { 1228 | "phpunit/phpunit": "^5.0" 1229 | }, 1230 | "type": "library", 1231 | "extra": { 1232 | "branch-alias": { 1233 | "dev-master": "2.0.x-dev" 1234 | } 1235 | }, 1236 | "autoload": { 1237 | "classmap": [ 1238 | "src/" 1239 | ] 1240 | }, 1241 | "notification-url": "https://packagist.org/downloads/", 1242 | "license": [ 1243 | "BSD-3-Clause" 1244 | ], 1245 | "authors": [ 1246 | { 1247 | "name": "Sebastian Bergmann", 1248 | "email": "sebastian@phpunit.de" 1249 | } 1250 | ], 1251 | "description": "Provides functionality to handle HHVM/PHP environments", 1252 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1253 | "keywords": [ 1254 | "Xdebug", 1255 | "environment", 1256 | "hhvm" 1257 | ], 1258 | "time": "2016-11-26 07:53:53" 1259 | }, 1260 | { 1261 | "name": "sebastian/exporter", 1262 | "version": "3.0.0", 1263 | "source": { 1264 | "type": "git", 1265 | "url": "https://github.com/sebastianbergmann/exporter.git", 1266 | "reference": "b82d077cb3459e393abcf4867ae8f7230dcb51f6" 1267 | }, 1268 | "dist": { 1269 | "type": "zip", 1270 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/b82d077cb3459e393abcf4867ae8f7230dcb51f6", 1271 | "reference": "b82d077cb3459e393abcf4867ae8f7230dcb51f6", 1272 | "shasum": "" 1273 | }, 1274 | "require": { 1275 | "php": "^7.0", 1276 | "sebastian/recursion-context": "^3.0" 1277 | }, 1278 | "require-dev": { 1279 | "ext-mbstring": "*", 1280 | "phpunit/phpunit": "^6.0" 1281 | }, 1282 | "type": "library", 1283 | "extra": { 1284 | "branch-alias": { 1285 | "dev-master": "3.0.x-dev" 1286 | } 1287 | }, 1288 | "autoload": { 1289 | "classmap": [ 1290 | "src/" 1291 | ] 1292 | }, 1293 | "notification-url": "https://packagist.org/downloads/", 1294 | "license": [ 1295 | "BSD-3-Clause" 1296 | ], 1297 | "authors": [ 1298 | { 1299 | "name": "Jeff Welch", 1300 | "email": "whatthejeff@gmail.com" 1301 | }, 1302 | { 1303 | "name": "Volker Dusch", 1304 | "email": "github@wallbash.com" 1305 | }, 1306 | { 1307 | "name": "Bernhard Schussek", 1308 | "email": "bschussek@2bepublished.at" 1309 | }, 1310 | { 1311 | "name": "Sebastian Bergmann", 1312 | "email": "sebastian@phpunit.de" 1313 | }, 1314 | { 1315 | "name": "Adam Harvey", 1316 | "email": "aharvey@php.net" 1317 | } 1318 | ], 1319 | "description": "Provides the functionality to export PHP variables for visualization", 1320 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1321 | "keywords": [ 1322 | "export", 1323 | "exporter" 1324 | ], 1325 | "time": "2017-03-03 06:25:06" 1326 | }, 1327 | { 1328 | "name": "sebastian/global-state", 1329 | "version": "1.1.1", 1330 | "source": { 1331 | "type": "git", 1332 | "url": "https://github.com/sebastianbergmann/global-state.git", 1333 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" 1334 | }, 1335 | "dist": { 1336 | "type": "zip", 1337 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", 1338 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", 1339 | "shasum": "" 1340 | }, 1341 | "require": { 1342 | "php": ">=5.3.3" 1343 | }, 1344 | "require-dev": { 1345 | "phpunit/phpunit": "~4.2" 1346 | }, 1347 | "suggest": { 1348 | "ext-uopz": "*" 1349 | }, 1350 | "type": "library", 1351 | "extra": { 1352 | "branch-alias": { 1353 | "dev-master": "1.0-dev" 1354 | } 1355 | }, 1356 | "autoload": { 1357 | "classmap": [ 1358 | "src/" 1359 | ] 1360 | }, 1361 | "notification-url": "https://packagist.org/downloads/", 1362 | "license": [ 1363 | "BSD-3-Clause" 1364 | ], 1365 | "authors": [ 1366 | { 1367 | "name": "Sebastian Bergmann", 1368 | "email": "sebastian@phpunit.de" 1369 | } 1370 | ], 1371 | "description": "Snapshotting of global state", 1372 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1373 | "keywords": [ 1374 | "global state" 1375 | ], 1376 | "time": "2015-10-12 03:26:01" 1377 | }, 1378 | { 1379 | "name": "sebastian/object-enumerator", 1380 | "version": "3.0.2", 1381 | "source": { 1382 | "type": "git", 1383 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1384 | "reference": "31dd3379d16446c5d86dec32ab1ad1f378581ad8" 1385 | }, 1386 | "dist": { 1387 | "type": "zip", 1388 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/31dd3379d16446c5d86dec32ab1ad1f378581ad8", 1389 | "reference": "31dd3379d16446c5d86dec32ab1ad1f378581ad8", 1390 | "shasum": "" 1391 | }, 1392 | "require": { 1393 | "php": "^7.0", 1394 | "sebastian/object-reflector": "^1.0", 1395 | "sebastian/recursion-context": "^3.0" 1396 | }, 1397 | "require-dev": { 1398 | "phpunit/phpunit": "^6.0" 1399 | }, 1400 | "type": "library", 1401 | "extra": { 1402 | "branch-alias": { 1403 | "dev-master": "3.0.x-dev" 1404 | } 1405 | }, 1406 | "autoload": { 1407 | "classmap": [ 1408 | "src/" 1409 | ] 1410 | }, 1411 | "notification-url": "https://packagist.org/downloads/", 1412 | "license": [ 1413 | "BSD-3-Clause" 1414 | ], 1415 | "authors": [ 1416 | { 1417 | "name": "Sebastian Bergmann", 1418 | "email": "sebastian@phpunit.de" 1419 | } 1420 | ], 1421 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1422 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1423 | "time": "2017-03-12 15:17:29" 1424 | }, 1425 | { 1426 | "name": "sebastian/object-reflector", 1427 | "version": "1.1.0", 1428 | "source": { 1429 | "type": "git", 1430 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1431 | "reference": "afd5797e7af7c9f529879ad5e8e8abe126c89dab" 1432 | }, 1433 | "dist": { 1434 | "type": "zip", 1435 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/afd5797e7af7c9f529879ad5e8e8abe126c89dab", 1436 | "reference": "afd5797e7af7c9f529879ad5e8e8abe126c89dab", 1437 | "shasum": "" 1438 | }, 1439 | "require": { 1440 | "php": "^7.0" 1441 | }, 1442 | "require-dev": { 1443 | "phpunit/phpunit": "^6.0" 1444 | }, 1445 | "type": "library", 1446 | "extra": { 1447 | "branch-alias": { 1448 | "dev-master": "1.1-dev" 1449 | } 1450 | }, 1451 | "autoload": { 1452 | "classmap": [ 1453 | "src/" 1454 | ] 1455 | }, 1456 | "notification-url": "https://packagist.org/downloads/", 1457 | "license": [ 1458 | "BSD-3-Clause" 1459 | ], 1460 | "authors": [ 1461 | { 1462 | "name": "Sebastian Bergmann", 1463 | "email": "sebastian@phpunit.de" 1464 | } 1465 | ], 1466 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 1467 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 1468 | "time": "2017-03-16 14:05:21" 1469 | }, 1470 | { 1471 | "name": "sebastian/recursion-context", 1472 | "version": "3.0.0", 1473 | "source": { 1474 | "type": "git", 1475 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1476 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" 1477 | }, 1478 | "dist": { 1479 | "type": "zip", 1480 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 1481 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 1482 | "shasum": "" 1483 | }, 1484 | "require": { 1485 | "php": "^7.0" 1486 | }, 1487 | "require-dev": { 1488 | "phpunit/phpunit": "^6.0" 1489 | }, 1490 | "type": "library", 1491 | "extra": { 1492 | "branch-alias": { 1493 | "dev-master": "3.0.x-dev" 1494 | } 1495 | }, 1496 | "autoload": { 1497 | "classmap": [ 1498 | "src/" 1499 | ] 1500 | }, 1501 | "notification-url": "https://packagist.org/downloads/", 1502 | "license": [ 1503 | "BSD-3-Clause" 1504 | ], 1505 | "authors": [ 1506 | { 1507 | "name": "Jeff Welch", 1508 | "email": "whatthejeff@gmail.com" 1509 | }, 1510 | { 1511 | "name": "Sebastian Bergmann", 1512 | "email": "sebastian@phpunit.de" 1513 | }, 1514 | { 1515 | "name": "Adam Harvey", 1516 | "email": "aharvey@php.net" 1517 | } 1518 | ], 1519 | "description": "Provides functionality to recursively process PHP variables", 1520 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1521 | "time": "2017-03-03 06:23:57" 1522 | }, 1523 | { 1524 | "name": "sebastian/resource-operations", 1525 | "version": "1.0.0", 1526 | "source": { 1527 | "type": "git", 1528 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1529 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" 1530 | }, 1531 | "dist": { 1532 | "type": "zip", 1533 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1534 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1535 | "shasum": "" 1536 | }, 1537 | "require": { 1538 | "php": ">=5.6.0" 1539 | }, 1540 | "type": "library", 1541 | "extra": { 1542 | "branch-alias": { 1543 | "dev-master": "1.0.x-dev" 1544 | } 1545 | }, 1546 | "autoload": { 1547 | "classmap": [ 1548 | "src/" 1549 | ] 1550 | }, 1551 | "notification-url": "https://packagist.org/downloads/", 1552 | "license": [ 1553 | "BSD-3-Clause" 1554 | ], 1555 | "authors": [ 1556 | { 1557 | "name": "Sebastian Bergmann", 1558 | "email": "sebastian@phpunit.de" 1559 | } 1560 | ], 1561 | "description": "Provides a list of PHP built-in functions that operate on resources", 1562 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1563 | "time": "2015-07-28 20:34:47" 1564 | }, 1565 | { 1566 | "name": "sebastian/version", 1567 | "version": "2.0.1", 1568 | "source": { 1569 | "type": "git", 1570 | "url": "https://github.com/sebastianbergmann/version.git", 1571 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" 1572 | }, 1573 | "dist": { 1574 | "type": "zip", 1575 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", 1576 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", 1577 | "shasum": "" 1578 | }, 1579 | "require": { 1580 | "php": ">=5.6" 1581 | }, 1582 | "type": "library", 1583 | "extra": { 1584 | "branch-alias": { 1585 | "dev-master": "2.0.x-dev" 1586 | } 1587 | }, 1588 | "autoload": { 1589 | "classmap": [ 1590 | "src/" 1591 | ] 1592 | }, 1593 | "notification-url": "https://packagist.org/downloads/", 1594 | "license": [ 1595 | "BSD-3-Clause" 1596 | ], 1597 | "authors": [ 1598 | { 1599 | "name": "Sebastian Bergmann", 1600 | "email": "sebastian@phpunit.de", 1601 | "role": "lead" 1602 | } 1603 | ], 1604 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1605 | "homepage": "https://github.com/sebastianbergmann/version", 1606 | "time": "2016-10-03 07:35:21" 1607 | }, 1608 | { 1609 | "name": "symfony/yaml", 1610 | "version": "v3.2.6", 1611 | "source": { 1612 | "type": "git", 1613 | "url": "https://github.com/symfony/yaml.git", 1614 | "reference": "093e416ad096355149e265ea2e4cc1f9ee40ab1a" 1615 | }, 1616 | "dist": { 1617 | "type": "zip", 1618 | "url": "https://api.github.com/repos/symfony/yaml/zipball/093e416ad096355149e265ea2e4cc1f9ee40ab1a", 1619 | "reference": "093e416ad096355149e265ea2e4cc1f9ee40ab1a", 1620 | "shasum": "" 1621 | }, 1622 | "require": { 1623 | "php": ">=5.5.9" 1624 | }, 1625 | "require-dev": { 1626 | "symfony/console": "~2.8|~3.0" 1627 | }, 1628 | "suggest": { 1629 | "symfony/console": "For validating YAML files using the lint command" 1630 | }, 1631 | "type": "library", 1632 | "extra": { 1633 | "branch-alias": { 1634 | "dev-master": "3.2-dev" 1635 | } 1636 | }, 1637 | "autoload": { 1638 | "psr-4": { 1639 | "Symfony\\Component\\Yaml\\": "" 1640 | }, 1641 | "exclude-from-classmap": [ 1642 | "/Tests/" 1643 | ] 1644 | }, 1645 | "notification-url": "https://packagist.org/downloads/", 1646 | "license": [ 1647 | "MIT" 1648 | ], 1649 | "authors": [ 1650 | { 1651 | "name": "Fabien Potencier", 1652 | "email": "fabien@symfony.com" 1653 | }, 1654 | { 1655 | "name": "Symfony Community", 1656 | "homepage": "https://symfony.com/contributors" 1657 | } 1658 | ], 1659 | "description": "Symfony Yaml Component", 1660 | "homepage": "https://symfony.com", 1661 | "time": "2017-03-07 16:47:02" 1662 | }, 1663 | { 1664 | "name": "webmozart/assert", 1665 | "version": "1.2.0", 1666 | "source": { 1667 | "type": "git", 1668 | "url": "https://github.com/webmozart/assert.git", 1669 | "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" 1670 | }, 1671 | "dist": { 1672 | "type": "zip", 1673 | "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", 1674 | "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", 1675 | "shasum": "" 1676 | }, 1677 | "require": { 1678 | "php": "^5.3.3 || ^7.0" 1679 | }, 1680 | "require-dev": { 1681 | "phpunit/phpunit": "^4.6", 1682 | "sebastian/version": "^1.0.1" 1683 | }, 1684 | "type": "library", 1685 | "extra": { 1686 | "branch-alias": { 1687 | "dev-master": "1.3-dev" 1688 | } 1689 | }, 1690 | "autoload": { 1691 | "psr-4": { 1692 | "Webmozart\\Assert\\": "src/" 1693 | } 1694 | }, 1695 | "notification-url": "https://packagist.org/downloads/", 1696 | "license": [ 1697 | "MIT" 1698 | ], 1699 | "authors": [ 1700 | { 1701 | "name": "Bernhard Schussek", 1702 | "email": "bschussek@gmail.com" 1703 | } 1704 | ], 1705 | "description": "Assertions to validate method input/output with nice error messages.", 1706 | "keywords": [ 1707 | "assert", 1708 | "check", 1709 | "validate" 1710 | ], 1711 | "time": "2016-11-23 20:04:58" 1712 | } 1713 | ], 1714 | "aliases": [], 1715 | "minimum-stability": "stable", 1716 | "stability-flags": [], 1717 | "prefer-stable": false, 1718 | "prefer-lowest": false, 1719 | "platform": [], 1720 | "platform-dev": [] 1721 | } 1722 | --------------------------------------------------------------------------------