├── .gitignore ├── vendor ├── joetannenbaum │ └── alfred-workflow │ │ ├── .gitignore │ │ ├── composer.json │ │ ├── .travis.yml │ │ ├── phpunit.xml │ │ ├── LICENSE.md │ │ ├── src │ │ ├── Workflow.php │ │ └── Result.php │ │ ├── README.md │ │ ├── tests │ │ └── WorkflowTest.php │ │ └── composer.lock ├── autoload.php └── composer │ ├── autoload_classmap.php │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── autoload_static.php │ ├── LICENSE │ ├── installed.json │ ├── autoload_real.php │ └── ClassLoader.php ├── icon.png ├── screenshot.png ├── workflow-variables.png ├── composer.json ├── LICENSE ├── composer.lock ├── README.md ├── find-messages.php └── info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .git/ 3 | .DS_Store 4 | 5 | -------------------------------------------------------------------------------- /vendor/joetannenbaum/alfred-workflow/.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squatto/alfred-imessage-2fa/HEAD/icon.png -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squatto/alfred-imessage-2fa/HEAD/screenshot.png -------------------------------------------------------------------------------- /workflow-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squatto/alfred-imessage-2fa/HEAD/workflow-variables.png -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | array($vendorDir . '/joetannenbaum/alfred-workflow/src'), 10 | ); 11 | -------------------------------------------------------------------------------- /vendor/joetannenbaum/alfred-workflow/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "joetannenbaum/alfred-workflow", 3 | "description": "PHP helper for creating Alfred Workflows.", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Joe Tannenbaum", 8 | "email": "joe@joe.codes" 9 | } 10 | ], 11 | "require": { 12 | "php": ">=5.4.0" 13 | }, 14 | "autoload": { 15 | "psr-4": { 16 | "Alfred\\Workflows\\": "src/" 17 | } 18 | }, 19 | "require-dev": { 20 | "phpunit/phpunit": "^5.3|~4.8" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /vendor/joetannenbaum/alfred-workflow/.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | sudo: false 3 | 4 | php: 5 | - 5.4 6 | - 5.5 7 | - 5.6 8 | - 7 9 | 10 | env: 11 | - COMPOSER_OPTS="" 12 | - COMPOSER_OPTS="--prefer-lowest" 13 | 14 | before_script: 15 | - travis_retry composer self-update 16 | - travis_retry composer update $COMPOSER_OPTS 17 | 18 | script: 19 | - vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover 20 | 21 | after_script: 22 | - wget https://scrutinizer-ci.com/ocular.phar 23 | - if [ "$TRAVIS_PHP_VERSION" != 7 ]; then php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi 24 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "squatto/alfred-imessage-2fa", 3 | "description": "Find two-factor authentication codes in your recent iMessage messages", 4 | "version": "1.3.0", 5 | "keywords": [ 6 | "alfred", 7 | "alfred-workflow", 8 | "2fa", 9 | "imessage" 10 | ], 11 | "homepage": "https://github.com/squatto/alfred-imessage-2fa", 12 | "support": { 13 | "source": "https://github.com/squatto/alfred-imessage-2fa", 14 | "issues": "https://github.com/squatto/alfred-imessage-2fa/issues" 15 | }, 16 | "license": "MIT", 17 | "require": { 18 | "joetannenbaum/alfred-workflow": "^0.1.0", 19 | "ext-pdo": "*" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /vendor/joetannenbaum/alfred-workflow/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | 11 | array ( 12 | 'Alfred\\Workflows\\' => 17, 13 | ), 14 | ); 15 | 16 | public static $prefixDirsPsr4 = array ( 17 | 'Alfred\\Workflows\\' => 18 | array ( 19 | 0 => __DIR__ . '/..' . '/joetannenbaum/alfred-workflow/src', 20 | ), 21 | ); 22 | 23 | public static function getInitializer(ClassLoader $loader) 24 | { 25 | return \Closure::bind(function () use ($loader) { 26 | $loader->prefixLengthsPsr4 = ComposerStaticInitd16a52b940a8c8cb97d16149984b3c2b::$prefixLengthsPsr4; 27 | $loader->prefixDirsPsr4 = ComposerStaticInitd16a52b940a8c8cb97d16149984b3c2b::$prefixDirsPsr4; 28 | 29 | }, null, ClassLoader::class); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /vendor/joetannenbaum/alfred-workflow/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Joe Tannenbaum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Till Krüss 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 | -------------------------------------------------------------------------------- /vendor/composer/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) Nils Adermann, Jordi Boggiano 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is furnished 9 | to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "joetannenbaum/alfred-workflow", 4 | "version": "0.1.2", 5 | "version_normalized": "0.1.2.0", 6 | "source": { 7 | "type": "git", 8 | "url": "https://github.com/joetannenbaum/alfred-workflow.git", 9 | "reference": "88e042db9cad0c95ab80e87c69d7f1e15340e7ac" 10 | }, 11 | "dist": { 12 | "type": "zip", 13 | "url": "https://api.github.com/repos/joetannenbaum/alfred-workflow/zipball/88e042db9cad0c95ab80e87c69d7f1e15340e7ac", 14 | "reference": "88e042db9cad0c95ab80e87c69d7f1e15340e7ac", 15 | "shasum": "" 16 | }, 17 | "require": { 18 | "php": ">=5.4.0" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "^5.3|~4.8" 22 | }, 23 | "time": "2018-08-14T14:25:53+00:00", 24 | "type": "library", 25 | "installation-source": "dist", 26 | "autoload": { 27 | "psr-4": { 28 | "Alfred\\Workflows\\": "src/" 29 | } 30 | }, 31 | "notification-url": "https://packagist.org/downloads/", 32 | "license": [ 33 | "MIT" 34 | ], 35 | "authors": [ 36 | { 37 | "name": "Joe Tannenbaum", 38 | "email": "joe@joe.codes" 39 | } 40 | ], 41 | "description": "PHP helper for creating Alfred Workflows." 42 | } 43 | ] 44 | -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | = 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); 27 | if ($useStaticLoader) { 28 | require_once __DIR__ . '/autoload_static.php'; 29 | 30 | call_user_func(\Composer\Autoload\ComposerStaticInitd16a52b940a8c8cb97d16149984b3c2b::getInitializer($loader)); 31 | } else { 32 | $map = require __DIR__ . '/autoload_namespaces.php'; 33 | foreach ($map as $namespace => $path) { 34 | $loader->set($namespace, $path); 35 | } 36 | 37 | $map = require __DIR__ . '/autoload_psr4.php'; 38 | foreach ($map as $namespace => $path) { 39 | $loader->setPsr4($namespace, $path); 40 | } 41 | 42 | $classMap = require __DIR__ . '/autoload_classmap.php'; 43 | if ($classMap) { 44 | $loader->addClassMap($classMap); 45 | } 46 | } 47 | 48 | $loader->register(true); 49 | 50 | return $loader; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /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#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "62218709de0c661d17242c7833d1fef1", 8 | "packages": [ 9 | { 10 | "name": "joetannenbaum/alfred-workflow", 11 | "version": "0.1.2", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/joetannenbaum/alfred-workflow.git", 15 | "reference": "88e042db9cad0c95ab80e87c69d7f1e15340e7ac" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/joetannenbaum/alfred-workflow/zipball/88e042db9cad0c95ab80e87c69d7f1e15340e7ac", 20 | "reference": "88e042db9cad0c95ab80e87c69d7f1e15340e7ac", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=5.4.0" 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": "^5.3|~4.8" 28 | }, 29 | "type": "library", 30 | "autoload": { 31 | "psr-4": { 32 | "Alfred\\Workflows\\": "src/" 33 | } 34 | }, 35 | "notification-url": "https://packagist.org/downloads/", 36 | "license": [ 37 | "MIT" 38 | ], 39 | "authors": [ 40 | { 41 | "name": "Joe Tannenbaum", 42 | "email": "joe@joe.codes" 43 | } 44 | ], 45 | "description": "PHP helper for creating Alfred Workflows.", 46 | "time": "2018-08-14T14:25:53+00:00" 47 | } 48 | ], 49 | "packages-dev": [], 50 | "aliases": [], 51 | "minimum-stability": "stable", 52 | "stability-flags": [], 53 | "prefer-stable": false, 54 | "prefer-lowest": false, 55 | "platform": { 56 | "ext-pdo": "*" 57 | }, 58 | "platform-dev": [] 59 | } 60 | -------------------------------------------------------------------------------- /vendor/joetannenbaum/alfred-workflow/src/Workflow.php: -------------------------------------------------------------------------------- 1 | results[] = $result; 20 | 21 | return $result; 22 | } 23 | 24 | /** 25 | * Add a variables to the workflow 26 | * 27 | * @param string $key 28 | * @param string $value 29 | * 30 | * @return \Alfred\Workflows\Workflow 31 | */ 32 | public function variable($key, $value) 33 | { 34 | $this->variables[$key] = $value; 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * Sort the current results 41 | * 42 | * @param string $direction 43 | * @param string $property 44 | * 45 | * @return \Alfred\Workflows\Workflow 46 | */ 47 | public function sortResults($direction = 'asc', $property = 'title') 48 | { 49 | usort($this->results, function ($a, $b) use ($direction, $property) { 50 | if ($direction === 'asc') { 51 | return $a->$property > $b->$property; 52 | } 53 | 54 | return $a->$property < $b->$property; 55 | }); 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * Filter current results (destructive) 62 | * 63 | * @param string $query 64 | * @param string $property 65 | * 66 | * @return \Alfred\Workflows\Workflow 67 | */ 68 | public function filterResults($query, $property = 'title') 69 | { 70 | if ($query === null || trim($query) === '') { 71 | return $this; 72 | } 73 | 74 | $query = (string) $query; 75 | 76 | $this->results = array_filter($this->results, function ($result) use ($query, $property) { 77 | return stristr($result->$property, $query) !== false; 78 | }); 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * Output the results as JSON 85 | * 86 | * @return string 87 | */ 88 | public function output() 89 | { 90 | $output = [ 91 | 'items' => array_map(function ($result) { 92 | return $result->toArray(); 93 | }, array_values($this->results)), 94 | ]; 95 | 96 | if(!empty($this->variables)){ 97 | $output['variables'] = $this->variables; 98 | }; 99 | 100 | return json_encode($output); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iMessage 2FA Workflow for Alfred 2 | 3 | Find two-factor authentication codes in your recent iMessage messages. 4 | 5 | ![Screenshot](screenshot.png) 6 | 7 | ## Requirements 8 | 9 | * `php` must be installed on your system 10 | * macOS has not had `php` preinstalled since Monterey (v12) 11 | * This is also the case for macOS Ventura (v13), Sonoma (v14), and Sequoia (v15) 12 | * We recommend using [Homebrew](https://brew.sh) to install `php` 13 | * To install Homebrew, follow the instructions on the "Install Homebrew" section of the [Homebrew website](https://brew.sh) 14 | * Once you have installed Homebrew, install `php` by running `brew install php` 15 | * You **MUST** grant Full Disk Access to Alfred 16 | * This is required because your messages are stored in the file `~/Library/Messages/chat.db`, which Alfred cannot read without having Full Disk Access 17 | * [See here for instructions on granting Full Disk Access to Alfred](https://www.alfredapp.com/help/getting-started/permissions/#full-disk) 18 | 19 | ## Installation 20 | 21 | 1. [Download the latest version of the workflow](https://github.com/squatto/alfred-imessage-2fa/releases/latest/download/iMessage.2FA.alfredworkflow) 22 | 2. Install the workflow by double-clicking the `.alfredworkflow` file 23 | 3. You can add the workflow to a category, then click "Import" to finish importing. You'll now see the workflow listed in the left sidebar of your Workflows preferences pane. 24 | 25 | ## Configuration 26 | 27 | * By default, only messages received in the past 15 minutes will be searched 28 | * You can change how many minutes to look back by changing the `look_back_minutes` workflow variable 29 | * Tutorial: [How to set workflow variables](https://www.alfredapp.com/help/workflows/advanced/variables/#environment) 30 | 31 | ![Workflow Variables](workflow-variables.png) 32 | 33 | ## Usage 34 | 35 | Type `2fm` to view the most recent two-factor authentication codes from iMessage messages. 36 | 37 | Select a 2FA code and do one of the following: 38 | 39 | * Press `` to copy it to your clipboard 40 | * Press `⌘+` (command + enter) to copy it to your clipboard and paste it into the active app window using simulated keystrokes 41 | * Some websites (e.g. Wells Fargo online banking) don't support pasting a 2FA code, so this will instead simulate typing the code 42 | * In order for this to work, you MUST grant Alfred automation access to `System Events`. If you haven't already done so, you will be prompted to grant access. [See here for more information about Alfred automation.](https://www.alfredapp.com/help/getting-started/permissions/#automation) 43 | * Press `⌥+` (option + enter) to copy it to your clipboard and paste it into the active app window using the system paste (similar to pressing `⌘+V`) 44 | 45 | ## Compatibility 46 | 47 | This workflow was developed for use with Alfred 5. It also works with Alfred 4. 48 | 49 | ## Contributors 50 | 51 | A huge thank you to our contributors! 52 | 53 | * [luckman212](https://github.com/luckman212) 54 | * [manonstreet](https://github.com/manonstreet) 55 | * [cmer](https://github.com/cmer) 56 | * [eruizdechavez](https://github.com/eruizdechavez) 57 | -------------------------------------------------------------------------------- /vendor/joetannenbaum/alfred-workflow/README.md: -------------------------------------------------------------------------------- 1 | # Alfred 3 Workflows PHP Helper 2 | 3 | [![Latest Version](https://img.shields.io/github/tag/joetannenbaum/alfred-workflow.svg?style=flat&label=release)](https://github.com/joetannenbaum/alfred-workflow/tags) 4 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](LICENSE.md) 5 | [![Build Status](https://travis-ci.org/joetannenbaum/alfred-workflow.svg?branch=master)](https://travis-ci.org/joetannenbaum/alfred-workflow) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/joetannenbaum/alfred-workflow.svg?style=flat)](https://packagist.org/packages/league/climate) 7 | 8 | This package simplifies PHP development for **Alfred 3** workflows. 9 | 10 | ## Installation 11 | 12 | ``` 13 | composer require joetannenbaum/alfred-workflow 14 | ``` 15 | 16 | ## Usage 17 | 18 | To understand the following properties, please reference the [official Alfred 3 documentation](https://www.alfredapp.com/help/workflows/inputs/script-filter/json/). 19 | 20 | The library is not doing any validation for required properties, so all of the following are optional. Please refer to the documentation above for required properties. All of the properties will default to the official defaults if excluded. 21 | 22 | ```php 23 | use Alfred\Workflows\Workflow; 24 | 25 | require 'vendor/autoload.php'; 26 | 27 | $workflow = new Workflow; 28 | 29 | // add variables 30 | $workflow->variable('fruit','apple') 31 | ->variable('vegetables','carrots'); 32 | 33 | $workflow->result() 34 | ->uid('bob-belcher') 35 | ->title('Bob') 36 | ->subtitle('Head Burger Chef') 37 | ->quicklookurl('http://www.bobsburgers.com') 38 | ->type('default') 39 | ->arg('bob') 40 | ->valid(true) 41 | ->icon('bob.png') 42 | ->mod('cmd', 'Search for Bob', 'search') 43 | ->text('copy', 'Bob is the best!') 44 | ->autocomplete('Bob Belcher'); 45 | 46 | $workflow->result() 47 | ->uid('linda-belcher') 48 | ->title('Linda') 49 | ->subtitle('Wife') 50 | ->quicklookurl('http://www.bobsburgers.com') 51 | ->type('default') 52 | ->arg('linda') 53 | ->valid(true) 54 | ->icon('linda.png') 55 | ->mod('cmd', 'Search for Linda', 'search') 56 | ->text('largetype', 'Linda is the best!') 57 | ->autocomplete('Linda Belcher'); 58 | 59 | echo $workflow->output(); 60 | ``` 61 | 62 | Results in: 63 | 64 | ```json 65 | { 66 | "items": [ 67 | { 68 | "arg": "bob", 69 | "autocomplete": "Bob Belcher", 70 | "icon": { 71 | "path": "bob.png" 72 | }, 73 | "mods": { 74 | "cmd": { 75 | "subtitle": "Search for Bob", 76 | "arg": "search", 77 | "valid": true 78 | } 79 | }, 80 | "quicklookurl": "http://www.bobsburgers.com", 81 | "subtitle": "Head Burger Chef", 82 | "text": { 83 | "copy": "Bob is the best!" 84 | }, 85 | "title": "Bob", 86 | "type": "default", 87 | "uid": "bob-belcher", 88 | "valid": true 89 | }, 90 | { 91 | "arg": "linda", 92 | "autocomplete": "Linda Belcher", 93 | "icon": { 94 | "path": "linda.png" 95 | }, 96 | "mods": { 97 | "cmd": { 98 | "subtitle": "Search for Linda", 99 | "arg": "search", 100 | "valid": true 101 | } 102 | }, 103 | "quicklookurl": "http://www.bobsburgers.com", 104 | "subtitle": "Wife", 105 | "text": { 106 | "largetype": "LINDA IS THE BEST!" 107 | }, 108 | "title": "Linda", 109 | "type": "default", 110 | "uid": "linda-belcher", 111 | "valid": true 112 | } 113 | ], 114 | "variables": { 115 | "fruit": "apple", 116 | "vegetables": "carrots" 117 | } 118 | } 119 | ``` 120 | 121 | ## Helper Methods 122 | 123 | Just for clarity, some helper methods exist. 124 | 125 | ```php 126 | // This... 127 | $workflow->result()->mod('cmd', 'Search for Bob', 'search'); 128 | // ...is the same as this. 129 | $workflow->result()->cmd('Search for Bob', 'search'); 130 | // And these are all available as well: 131 | $workflow->result()->shift('Search for Bob', 'search'); 132 | $workflow->result()->fn('Search for Bob', 'search'); 133 | $workflow->result()->ctrl('Search for Bob', 'search'); 134 | $workflow->result()->alt('Search for Bob', 'search'); 135 | ``` 136 | 137 | ```php 138 | // This... 139 | $workflow->result()->text('largetype', 'Linda is the best!') 140 | // ...is the same as this. 141 | $workflow->result()->largetype('Linda is the best!'); 142 | // Also works: 143 | $workflow->result()->copy('Linda is the best!'); 144 | ``` 145 | 146 | ```php 147 | // This... 148 | $workflow->result()->icon('bob.png', 'fileicon') 149 | // ...is the same as this. 150 | $workflow->result()->fileiconIcon('bob.png') 151 | // Also works: 152 | $workflow->result()->filetypeIcon('bob.png') 153 | ``` 154 | 155 | ## Sorting 156 | 157 | If you'd like to sort your results: 158 | 159 | ```php 160 | // Default is by title asc: 161 | $workflow->sortResults(); 162 | // Title desc: 163 | $workflow->sortResults('desc'); 164 | // By property asc: 165 | $workflow->sortResults('asc', 'subtitle'); 166 | ``` 167 | 168 | ## Filtering 169 | 170 | You can filter your results as well if Alfred isn't doing it for you: 171 | 172 | **Please note** this is a very simple filtering, literally looking for the string within the string. For anything more complex filter before creating results. 173 | 174 | ```php 175 | // Default is searching in title: 176 | $workflow->filterResults('bob'); 177 | // By property: 178 | $workflow->filterResults('bob', 'subtitle'); 179 | ``` 180 | -------------------------------------------------------------------------------- /vendor/joetannenbaum/alfred-workflow/src/Result.php: -------------------------------------------------------------------------------- 1 | valid = !!$valid; 39 | 40 | return $this; 41 | } 42 | 43 | /** 44 | * @param string $type (deafult|file|file:skipcheck) 45 | * @param bool $verify_existence When used with $type 'file' 46 | * 47 | * @return \Alfred\Workflows\Result 48 | */ 49 | protected function setType($type, $verify_existence = true) 50 | { 51 | if (in_array($type, ['default', 'file', 'file:skipcheck'])) { 52 | if ($type === 'file' && $verify_existence === false) { 53 | $type = 'file:skipcheck'; 54 | } 55 | 56 | $this->type = $type; 57 | } 58 | 59 | return $this; 60 | } 61 | 62 | /** 63 | * @param string $path 64 | * @param string|null $type (fileicon|filetype) 65 | * 66 | * @return \Alfred\Workflows\Result 67 | */ 68 | protected function setIcon($path, $type = null) 69 | { 70 | $this->icon = [ 71 | 'path' => $path, 72 | ]; 73 | 74 | if (in_array($type, ['fileicon', 'filetype'])) { 75 | $this->icon['type'] = $type; 76 | } 77 | 78 | return $this; 79 | } 80 | 81 | /** 82 | * @param string $path 83 | * 84 | * @return \Alfred\Workflows\Result 85 | */ 86 | protected function setFileiconIcon($path) 87 | { 88 | return $this->setIcon($path, 'fileicon'); 89 | } 90 | 91 | /** 92 | * @param string $path 93 | * 94 | * @return \Alfred\Workflows\Result 95 | */ 96 | protected function setFiletypeIcon($path) 97 | { 98 | return $this->setIcon($path, 'filetype'); 99 | } 100 | 101 | /** 102 | * @param string $subtitle 103 | * 104 | * @return \Alfred\Workflows\Result 105 | */ 106 | protected function setSubtitle($subtitle) 107 | { 108 | $this->subtitle = $subtitle; 109 | 110 | return $this; 111 | } 112 | 113 | /** 114 | * @param string $type (copy|largetype) 115 | * @param string $text 116 | * 117 | * @return \Alfred\Workflows\Result 118 | */ 119 | protected function setText($type, $text) 120 | { 121 | if (!in_array($type, ['copy', 'largetype'])) { 122 | return $this; 123 | } 124 | 125 | $this->text[$type] = $text; 126 | 127 | return $this; 128 | } 129 | 130 | /** 131 | * @param string $copy 132 | * 133 | * @return \Alfred\Workflows\Result 134 | */ 135 | protected function setCopy($copy) 136 | { 137 | return $this->setText('copy', $copy); 138 | } 139 | 140 | /** 141 | * @param string $largetype 142 | * 143 | * @return \Alfred\Workflows\Result 144 | */ 145 | protected function setLargetype($largetype) 146 | { 147 | return $this->setText('largetype', $largetype); 148 | } 149 | 150 | /** 151 | * @param string $mod (shift|fn|ctrl|alt|cmd) 152 | * @param string $subtitle 153 | * @param string $arg 154 | * @param bool $valid 155 | * 156 | * @return \Alfred\Workflows\Result 157 | */ 158 | protected function setMod($mod, $subtitle, $arg, $valid = true) 159 | { 160 | if (!in_array($mod, ['shift', 'fn', 'ctrl', 'alt', 'cmd'])) { 161 | return $this; 162 | } 163 | 164 | $this->mods[$mod] = compact('subtitle', 'arg', 'valid'); 165 | 166 | return $this; 167 | } 168 | 169 | /** 170 | * @param string $subtitle 171 | * @param string $arg 172 | * @param bool $valid 173 | * 174 | * @return \Alfred\Workflows\Result 175 | */ 176 | protected function setCmd($subtitle, $arg, $valid = true) 177 | { 178 | return $this->setMod('cmd', $subtitle, $arg, $valid); 179 | } 180 | 181 | /** 182 | * @param string $subtitle 183 | * @param string $arg 184 | * @param bool $valid 185 | * 186 | * @return \Alfred\Workflows\Result 187 | */ 188 | protected function setShift($subtitle, $arg, $valid = true) 189 | { 190 | return $this->setMod('shift', $subtitle, $arg, $valid); 191 | } 192 | 193 | /** 194 | * @param string $subtitle 195 | * @param string $arg 196 | * @param bool $valid 197 | * 198 | * @return \Alfred\Workflows\Result 199 | */ 200 | protected function setFn($subtitle, $arg, $valid = true) 201 | { 202 | return $this->setMod('fn', $subtitle, $arg, $valid); 203 | } 204 | 205 | /** 206 | * @param string $subtitle 207 | * @param string $arg 208 | * @param bool $valid 209 | * 210 | * @return \Alfred\Workflows\Result 211 | */ 212 | protected function setCtrl($subtitle, $arg, $valid = true) 213 | { 214 | return $this->setMod('ctrl', $subtitle, $arg, $valid); 215 | } 216 | 217 | /** 218 | * @param string $subtitle 219 | * @param string $arg 220 | * @param bool $valid 221 | * 222 | * @return \Alfred\Workflows\Result 223 | */ 224 | protected function setAlt($subtitle, $arg, $valid = true) 225 | { 226 | return $this->setMod('alt', $subtitle, $arg, $valid); 227 | } 228 | 229 | /** 230 | * Converts the results to an array structured for Alfred 231 | * 232 | * @return array 233 | */ 234 | public function toArray() 235 | { 236 | $attrs = [ 237 | 'uid', 238 | 'arg', 239 | 'autocomplete', 240 | 'title', 241 | 'subtitle', 242 | 'type', 243 | 'valid', 244 | 'quicklookurl', 245 | 'icon', 246 | 'mods', 247 | 'text', 248 | ]; 249 | 250 | $result = []; 251 | 252 | foreach ($attrs as $attr) { 253 | if (is_array($this->$attr)) { 254 | if (count($this->$attr) > 0) { 255 | $result[$attr] = $this->$attr; 256 | } 257 | continue; 258 | } 259 | 260 | if ($this->$attr !== null) { 261 | $result[$attr] = $this->$attr; 262 | } 263 | } 264 | 265 | ksort($result); 266 | 267 | return $result; 268 | } 269 | 270 | public function __get($property) 271 | { 272 | return $this->$property; 273 | } 274 | 275 | public function __call($method, $args) 276 | { 277 | $setter = 'set' . ucwords($method); 278 | 279 | if (method_exists($this, $setter)) { 280 | call_user_func_array([$this, $setter], $args); 281 | 282 | return $this; 283 | } 284 | 285 | if (property_exists($this, $method)) { 286 | $this->$method = reset($args); 287 | 288 | return $this; 289 | } 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /find-messages.php: -------------------------------------------------------------------------------- 1 | result() 16 | ->title('ERROR: Unable to Access Your Messages') 17 | ->subtitle('We were unable to access the file that contains your text messages') 18 | ->arg('') 19 | ->valid(true); 20 | echo $workflow->output(); 21 | exit; 22 | } 23 | 24 | try { 25 | $db = new PDO('sqlite:' . $dbPath); 26 | $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 27 | } catch (PDOException $e) { 28 | $workflow->result() 29 | ->title('ERROR: Unable to Access Your Messages') 30 | ->subtitle('We were unable to access the file that contains your text messages') 31 | ->arg('') 32 | ->valid(true); 33 | $workflow->result() 34 | ->title('Error Message:') 35 | ->subtitle($e->getMessage()) 36 | ->arg('') 37 | ->valid(true); 38 | echo $workflow->output(); 39 | exit; 40 | } 41 | 42 | try { 43 | $query = $db->query(" 44 | select 45 | message.rowid, 46 | ifnull(handle.uncanonicalized_id, chat.chat_identifier) AS sender, 47 | message.service, 48 | datetime(message.date / 1000000000 + 978307200, 'unixepoch', 'localtime') AS message_date, 49 | message.text 50 | from 51 | message 52 | left join chat_message_join 53 | on chat_message_join.message_id = message.ROWID 54 | left join chat 55 | on chat.ROWID = chat_message_join.chat_id 56 | left join handle 57 | on message.handle_id = handle.ROWID 58 | where 59 | message.is_from_me = 0 60 | and message.text is not null 61 | and length(message.text) > 0 62 | and ( 63 | message.text glob '*[0-9][0-9][0-9]*' 64 | or message.text glob '*[0-9][0-9][0-9][0-9]*' 65 | or message.text glob '*[0-9][0-9][0-9][0-9][0-9]*' 66 | or message.text glob '*[0-9][0-9][0-9][0-9][0-9][0-9]*' 67 | or message.text glob '*[0-9][0-9][0-9]-[0-9][0-9][0-9]*' 68 | or message.text glob '*[0-9][0-9][0-9][0-9][0-9][0-9][0-9]*' 69 | or message.text glob '*[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]*' 70 | ) 71 | and datetime(message.date / 1000000000 + strftime('%s', '2001-01-01'), 'unixepoch', 'localtime') 72 | >= datetime('now', '-$lookBackMinutes minutes', 'localtime') 73 | order by 74 | message.date desc 75 | limit 100 76 | "); 77 | } catch (PDOException $e) { 78 | $workflow->result() 79 | ->title('ERROR: Unable to Query Your Messages') 80 | ->subtitle('We were unable to run the query that reads your text messages') 81 | ->arg('') 82 | ->valid(true); 83 | $workflow->result() 84 | ->title('Error Message:') 85 | ->subtitle($e->getMessage()) 86 | ->arg('') 87 | ->valid(true); 88 | echo $workflow->output(); 89 | exit; 90 | } 91 | 92 | $found = 0; 93 | $max = 8; 94 | 95 | while ($message = $query->fetch(PDO::FETCH_ASSOC)) { 96 | $code = null; 97 | $text = $message['text']; 98 | 99 | // remove URLs 100 | $text = preg_replace('/\b((https?|ftp|file):\/\/|www\.)[-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i', '', $text); 101 | 102 | // skip now-empty messages 103 | $text = trim($text); 104 | 105 | if (empty($text)) { 106 | continue; 107 | } 108 | 109 | if (preg_match('/(^|\s|\R|\t|\b|G-|:)(\d{5,8})($|\s|\R|\t|\b|\.|,)/', $text, $matches)) { 110 | // 5-8 consecutive digits 111 | // examples: 112 | // "您的验证码是 199035,10分钟内有效,请勿泄露" 113 | // "登录验证码:627823,您正在尝试【登录】,10分钟内有效" 114 | // "【赛验】验证码 54538" 115 | // "Enter this code to log in:59678." 116 | // "G-315643 is your Google verification code" 117 | // "Enter the code 765432, and then click the button to log in." 118 | // "Your code is 45678!" 119 | // "Your code is:98765!" 120 | $code = $matches[2]; 121 | } elseif (preg_match('/^(\d{4,8})(\sis your.*code)/', $text, $matches)) { 122 | // 4-8 digits followed by "is your [...] code" 123 | // examples: 124 | // "2773 is your Microsoft account verification code" 125 | $code = $matches[1]; 126 | } elseif (preg_match('/(code:|is:)\s*(\d{4,8})($|\s|\R|\t|\b|\.|,)/i', $text, $matches)) { 127 | // "code:" OR "is:", optional whitespace, then 4-8 consecutive digits 128 | // examples: 129 | // "Your Airbnb verification code is: 1234." 130 | // "Your verification code is: 1234, use it to log in" 131 | // "Here is your authorization code:9384" 132 | $code = $matches[2]; 133 | } elseif (preg_match('/(code|is):?\s*(\d{3,8})($|\s|\R|\t|\b|\.|,)/i', $text, $matches)) { 134 | // "code" OR "is" followed by an optional ":" + optional whitespace, then 3-8 consecutive digits 135 | // examples: 136 | // "Please enter code 548 on Zocdoc." 137 | $code = $matches[2]; 138 | } elseif (preg_match('/(^|code:|is:|\b)\s*(\d{3})-(\d{3})($|\s|\R|\t|\b|\.|,)/', $text, $matches)) { 139 | // line beginning OR "code:" OR "is:" OR word boundary, optional whitespace, 3 consecutive digits, a hyphen, then 3 consecutive digits 140 | // but NOT a phone number (###-###-####) 141 | // examples: 142 | // "123-456" 143 | // "Your Stripe verification code is: 719-839." 144 | $first = $matches[2]; 145 | $second = $matches[3]; 146 | 147 | // make sure it isn't a phone number 148 | // doesn't match: --<4 consecutive digits> 149 | if (! preg_match('/(^|code:|is:|\b)\s*' . $first . '-' . $second . '-(\d{4})($|\s|\R|\t|\b|\.|,)/', $text, $matches)) { 150 | $code = $first . $second; 151 | } 152 | } 153 | 154 | if ($code) { 155 | $found++; 156 | $date = formatDate($message['message_date']); 157 | $text = formatText($message['text']); 158 | $sender = formatSender($message['sender']); 159 | 160 | $workflow->result() 161 | ->title($code) 162 | ->subtitle("$date from $sender: $text") 163 | ->arg($code) 164 | ->valid(true); 165 | 166 | if ($found >= $max) { 167 | break; 168 | } 169 | } 170 | } 171 | 172 | if (! $found) { 173 | $workflow->result() 174 | ->title('No 2FA Codes Found') 175 | ->subtitle("No two-factor auth codes were found in your text messages from the past $lookBackMinutes minutes") 176 | ->arg('') 177 | ->valid(true); 178 | } 179 | 180 | echo $workflow->output(); 181 | 182 | /** 183 | * Format the date of the message 184 | * 185 | * @param string $date 186 | * 187 | * @return string 188 | */ 189 | function formatDate($date) 190 | { 191 | $time = strtotime($date); 192 | 193 | if (date('m/d/Y', $time) === date('m/d/Y')) { 194 | return 'Today @ ' . date('g:ia', $time); 195 | } 196 | 197 | return date('M j @ g:ia', $time); 198 | } 199 | 200 | /** 201 | * Format the text of the message 202 | * 203 | * @param string $text 204 | * 205 | * @return string 206 | */ 207 | function formatText($text) 208 | { 209 | return str_replace( 210 | ["\n", ':;'], 211 | ['; ', ':'], 212 | trim($text) 213 | ); 214 | } 215 | 216 | /** 217 | * Format a sender number 218 | * 219 | * @param string $sender 220 | * 221 | * @return string 222 | */ 223 | function formatSender($sender) 224 | { 225 | $sender = trim($sender, '+'); 226 | 227 | if (strlen($sender) === 11 && substr($sender, 0, 1) === '1') { 228 | $sender = substr($sender, 1); 229 | } 230 | 231 | if (strlen($sender) === 10) { 232 | return substr($sender, 0, 3) . '-' . substr($sender, 3, 3) . '-' . substr($sender, 6, 4); 233 | } 234 | 235 | return $sender; 236 | } 237 | -------------------------------------------------------------------------------- /info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | co.bluehelix.imessage-2fa 7 | category 8 | Tools 9 | connections 10 | 11 | 7B86D057-DA8E-4302-AF17-83B889B48EE2 12 | 13 | 14 | destinationuid 15 | 579C566A-EAC9-4F0C-A398-0A4D25EB7251 16 | modifiers 17 | 0 18 | modifiersubtext 19 | 20 | vitoclose 21 | 22 | 23 | 24 | destinationuid 25 | 3D26FE0D-9464-426E-8EAA-03376F20B9CA 26 | modifiers 27 | 0 28 | modifiersubtext 29 | 30 | vitoclose 31 | 32 | 33 | 34 | destinationuid 35 | F66B4E67-AAD4-4597-9902-E084CCFAE32F 36 | modifiers 37 | 1048576 38 | modifiersubtext 39 | Copy the code and paste it into the active app with simulated keystrokes 40 | vitoclose 41 | 42 | 43 | 44 | destinationuid 45 | 42B9D6A1-ACF9-4562-9718-B4A1C983D5AA 46 | modifiers 47 | 524288 48 | modifiersubtext 49 | Copy the code and paste it into the active app with a system paste 50 | vitoclose 51 | 52 | 53 | 54 | F66B4E67-AAD4-4597-9902-E084CCFAE32F 55 | 56 | 57 | destinationuid 58 | 3E71F597-EA2F-4B39-B8E4-69A3D625872E 59 | modifiers 60 | 0 61 | modifiersubtext 62 | 63 | vitoclose 64 | 65 | 66 | 67 | 68 | createdby 69 | Scott Carpenter 70 | description 71 | Find two-factor authentication codes in your recent iMessage messages 72 | disabled 73 | 74 | name 75 | iMessage 2FA 76 | objects 77 | 78 | 79 | config 80 | 81 | alfredfiltersresults 82 | 83 | alfredfiltersresultsmatchmode 84 | 0 85 | argumenttreatemptyqueryasnil 86 | 87 | argumenttrimmode 88 | 0 89 | argumenttype 90 | 2 91 | escaping 92 | 4 93 | keyword 94 | 2fm 95 | queuedelaycustom 96 | 3 97 | queuedelayimmediatelyinitially 98 | 99 | queuedelaymode 100 | 0 101 | queuemode 102 | 1 103 | runningsubtext 104 | Finding two-factor authentication codes... 105 | script 106 | #!/bin/bash 107 | 108 | if ! hash php 2> /dev/null; then 109 | cat <<- EOB 110 | {"items": [ 111 | { 112 | "arg": "https://brew.sh", 113 | "title": "ERROR: PHP is not installed on your system", 114 | "subtitle": "Please install php. We recommend using Homebrew: https://brew.sh", 115 | "valid": true 116 | } 117 | ]} 118 | EOB 119 | 120 | exit 1 121 | fi 122 | 123 | php find-messages.php $look_back_minutes 124 | 125 | scriptargtype 126 | 1 127 | scriptfile 128 | 129 | subtext 130 | Find two-factor authentication codes... 131 | title 132 | iMessage 2FA 133 | type 134 | 0 135 | withspace 136 | 137 | 138 | type 139 | alfred.workflow.input.scriptfilter 140 | uid 141 | 7B86D057-DA8E-4302-AF17-83B889B48EE2 142 | version 143 | 3 144 | 145 | 146 | config 147 | 148 | lastpathcomponent 149 | 150 | onlyshowifquerypopulated 151 | 152 | removeextension 153 | 154 | text 155 | Copied 2FA code "{query}" to clipboard 156 | title 157 | iMessage 2FA 158 | 159 | type 160 | alfred.workflow.output.notification 161 | uid 162 | 579C566A-EAC9-4F0C-A398-0A4D25EB7251 163 | version 164 | 1 165 | 166 | 167 | config 168 | 169 | autopaste 170 | 171 | clipboardtext 172 | {query} 173 | ignoredynamicplaceholders 174 | 175 | transient 176 | 177 | 178 | type 179 | alfred.workflow.output.clipboard 180 | uid 181 | 3D26FE0D-9464-426E-8EAA-03376F20B9CA 182 | version 183 | 3 184 | 185 | 186 | config 187 | 188 | autopaste 189 | 190 | clipboardtext 191 | {query} 192 | ignoredynamicplaceholders 193 | 194 | transient 195 | 196 | 197 | type 198 | alfred.workflow.output.clipboard 199 | uid 200 | F66B4E67-AAD4-4597-9902-E084CCFAE32F 201 | version 202 | 3 203 | 204 | 205 | config 206 | 207 | concurrently 208 | 209 | escaping 210 | 102 211 | script 212 | osascript -e 'tell application "System Events" to keystroke the clipboard as text' 213 | scriptargtype 214 | 1 215 | scriptfile 216 | 217 | type 218 | 0 219 | 220 | type 221 | alfred.workflow.action.script 222 | uid 223 | 3E71F597-EA2F-4B39-B8E4-69A3D625872E 224 | version 225 | 2 226 | 227 | 228 | config 229 | 230 | autopaste 231 | 232 | clipboardtext 233 | {query} 234 | ignoredynamicplaceholders 235 | 236 | transient 237 | 238 | 239 | type 240 | alfred.workflow.output.clipboard 241 | uid 242 | 42B9D6A1-ACF9-4562-9718-B4A1C983D5AA 243 | version 244 | 3 245 | 246 | 247 | readme 248 | Find two-factor authentication codes in your recent iMessage messages. 249 | 250 | ## Requirements 251 | 252 | * `php` must be installed on your system 253 | * macOS has not had `php` preinstalled since Monterey (v12) 254 | * This is also the case for macOS Ventura (v13), Sonoma (v14), and Sequoia (v15) 255 | * We recommend using [Homebrew](https://brew.sh) to install `php` 256 | * To install Homebrew, follow the instructions on the "Install Homebrew" section of the [Homebrew website](https://brew.sh) 257 | * Once you have installed Homebrew, install `php` by running `brew install php` 258 | * You **MUST** grant Full Disk Access to Alfred 259 | * This is required because your messages are stored in the file `~/Library/Messages/chat.db`, which Alfred cannot read without having Full Disk Access 260 | * [See here for instructions on granting Full Disk Access to Alfred](https://www.alfredapp.com/help/getting-started/permissions/#full-disk) 261 | 262 | ## Configuration 263 | 264 | * By default, only messages received in the past 15 minutes will be searched 265 | * You can change how many minutes to look back by changing the `look_back_minutes` workflow variable 266 | * Tutorial: [How to set workflow variables](https://www.alfredapp.com/help/workflows/advanced/variables/#environment) 267 | 268 | ## Usage 269 | 270 | Type `2fm` to view the most recent two-factor authentication codes from iMessage messages. 271 | 272 | Select a 2FA code and do one of the following: 273 | 274 | * Press `<enter>` to copy it to your clipboard 275 | * Press `⌘+<enter>` (command + enter) to copy it to your clipboard and paste it into the active app window using simulated keystrokes 276 | * Some websites (e.g. Wells Fargo online banking) don't support pasting a 2FA code, so this will instead simulate typing the code 277 | * In order for this to work, you MUST grant Alfred automation access to `System Events`. If you haven't already done so, you will be prompted to grant access. [See here for more information about Alfred automation.](https://www.alfredapp.com/help/getting-started/permissions/#automation) 278 | * Press `⌥+<enter>` (option + enter) to copy it to your clipboard and paste it into the active app window using the system paste (similar to pressing `⌘+V`) 279 | uidata 280 | 281 | 3D26FE0D-9464-426E-8EAA-03376F20B9CA 282 | 283 | note 284 | Only copy to clipboard 285 | xpos 286 | 325 287 | ypos 288 | 190 289 | 290 | 3E71F597-EA2F-4B39-B8E4-69A3D625872E 291 | 292 | xpos 293 | 485 294 | ypos 295 | 335 296 | 297 | 42B9D6A1-ACF9-4562-9718-B4A1C983D5AA 298 | 299 | note 300 | Method 2: Alfred paste 301 | xpos 302 | 325 303 | ypos 304 | 505 305 | 306 | 579C566A-EAC9-4F0C-A398-0A4D25EB7251 307 | 308 | xpos 309 | 325 310 | ypos 311 | 70 312 | 313 | 7B86D057-DA8E-4302-AF17-83B889B48EE2 314 | 315 | xpos 316 | 70 317 | ypos 318 | 70 319 | 320 | F66B4E67-AAD4-4597-9902-E084CCFAE32F 321 | 322 | note 323 | Method 1: AppleScript paste to simulate keystrokes 324 | xpos 325 | 325 326 | ypos 327 | 335 328 | 329 | 330 | userconfigurationconfig 331 | 332 | variables 333 | 334 | look_back_minutes 335 | 15 336 | 337 | version 338 | 1.3.0 339 | webaddress 340 | https://github.com/squatto/alfred-imessage-2fa/ 341 | 342 | 343 | -------------------------------------------------------------------------------- /vendor/composer/ClassLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Autoload; 14 | 15 | /** 16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. 17 | * 18 | * $loader = new \Composer\Autoload\ClassLoader(); 19 | * 20 | * // register classes with namespaces 21 | * $loader->add('Symfony\Component', __DIR__.'/component'); 22 | * $loader->add('Symfony', __DIR__.'/framework'); 23 | * 24 | * // activate the autoloader 25 | * $loader->register(); 26 | * 27 | * // to enable searching the include path (eg. for PEAR packages) 28 | * $loader->setUseIncludePath(true); 29 | * 30 | * In this example, if you try to use a class in the Symfony\Component 31 | * namespace or one of its children (Symfony\Component\Console for instance), 32 | * the autoloader will first look for the class under the component/ 33 | * directory, and it will then fallback to the framework/ directory if not 34 | * found before giving up. 35 | * 36 | * This class is loosely based on the Symfony UniversalClassLoader. 37 | * 38 | * @author Fabien Potencier 39 | * @author Jordi Boggiano 40 | * @see http://www.php-fig.org/psr/psr-0/ 41 | * @see http://www.php-fig.org/psr/psr-4/ 42 | */ 43 | class ClassLoader 44 | { 45 | // PSR-4 46 | private $prefixLengthsPsr4 = array(); 47 | private $prefixDirsPsr4 = array(); 48 | private $fallbackDirsPsr4 = array(); 49 | 50 | // PSR-0 51 | private $prefixesPsr0 = array(); 52 | private $fallbackDirsPsr0 = array(); 53 | 54 | private $useIncludePath = false; 55 | private $classMap = array(); 56 | private $classMapAuthoritative = false; 57 | private $missingClasses = array(); 58 | private $apcuPrefix; 59 | 60 | public function getPrefixes() 61 | { 62 | if (!empty($this->prefixesPsr0)) { 63 | return call_user_func_array('array_merge', $this->prefixesPsr0); 64 | } 65 | 66 | return array(); 67 | } 68 | 69 | public function getPrefixesPsr4() 70 | { 71 | return $this->prefixDirsPsr4; 72 | } 73 | 74 | public function getFallbackDirs() 75 | { 76 | return $this->fallbackDirsPsr0; 77 | } 78 | 79 | public function getFallbackDirsPsr4() 80 | { 81 | return $this->fallbackDirsPsr4; 82 | } 83 | 84 | public function getClassMap() 85 | { 86 | return $this->classMap; 87 | } 88 | 89 | /** 90 | * @param array $classMap Class to filename map 91 | */ 92 | public function addClassMap(array $classMap) 93 | { 94 | if ($this->classMap) { 95 | $this->classMap = array_merge($this->classMap, $classMap); 96 | } else { 97 | $this->classMap = $classMap; 98 | } 99 | } 100 | 101 | /** 102 | * Registers a set of PSR-0 directories for a given prefix, either 103 | * appending or prepending to the ones previously set for this prefix. 104 | * 105 | * @param string $prefix The prefix 106 | * @param array|string $paths The PSR-0 root directories 107 | * @param bool $prepend Whether to prepend the directories 108 | */ 109 | public function add($prefix, $paths, $prepend = false) 110 | { 111 | if (!$prefix) { 112 | if ($prepend) { 113 | $this->fallbackDirsPsr0 = array_merge( 114 | (array) $paths, 115 | $this->fallbackDirsPsr0 116 | ); 117 | } else { 118 | $this->fallbackDirsPsr0 = array_merge( 119 | $this->fallbackDirsPsr0, 120 | (array) $paths 121 | ); 122 | } 123 | 124 | return; 125 | } 126 | 127 | $first = $prefix[0]; 128 | if (!isset($this->prefixesPsr0[$first][$prefix])) { 129 | $this->prefixesPsr0[$first][$prefix] = (array) $paths; 130 | 131 | return; 132 | } 133 | if ($prepend) { 134 | $this->prefixesPsr0[$first][$prefix] = array_merge( 135 | (array) $paths, 136 | $this->prefixesPsr0[$first][$prefix] 137 | ); 138 | } else { 139 | $this->prefixesPsr0[$first][$prefix] = array_merge( 140 | $this->prefixesPsr0[$first][$prefix], 141 | (array) $paths 142 | ); 143 | } 144 | } 145 | 146 | /** 147 | * Registers a set of PSR-4 directories for a given namespace, either 148 | * appending or prepending to the ones previously set for this namespace. 149 | * 150 | * @param string $prefix The prefix/namespace, with trailing '\\' 151 | * @param array|string $paths The PSR-4 base directories 152 | * @param bool $prepend Whether to prepend the directories 153 | * 154 | * @throws \InvalidArgumentException 155 | */ 156 | public function addPsr4($prefix, $paths, $prepend = false) 157 | { 158 | if (!$prefix) { 159 | // Register directories for the root namespace. 160 | if ($prepend) { 161 | $this->fallbackDirsPsr4 = array_merge( 162 | (array) $paths, 163 | $this->fallbackDirsPsr4 164 | ); 165 | } else { 166 | $this->fallbackDirsPsr4 = array_merge( 167 | $this->fallbackDirsPsr4, 168 | (array) $paths 169 | ); 170 | } 171 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { 172 | // Register directories for a new namespace. 173 | $length = strlen($prefix); 174 | if ('\\' !== $prefix[$length - 1]) { 175 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 176 | } 177 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 178 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 179 | } elseif ($prepend) { 180 | // Prepend directories for an already registered namespace. 181 | $this->prefixDirsPsr4[$prefix] = array_merge( 182 | (array) $paths, 183 | $this->prefixDirsPsr4[$prefix] 184 | ); 185 | } else { 186 | // Append directories for an already registered namespace. 187 | $this->prefixDirsPsr4[$prefix] = array_merge( 188 | $this->prefixDirsPsr4[$prefix], 189 | (array) $paths 190 | ); 191 | } 192 | } 193 | 194 | /** 195 | * Registers a set of PSR-0 directories for a given prefix, 196 | * replacing any others previously set for this prefix. 197 | * 198 | * @param string $prefix The prefix 199 | * @param array|string $paths The PSR-0 base directories 200 | */ 201 | public function set($prefix, $paths) 202 | { 203 | if (!$prefix) { 204 | $this->fallbackDirsPsr0 = (array) $paths; 205 | } else { 206 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; 207 | } 208 | } 209 | 210 | /** 211 | * Registers a set of PSR-4 directories for a given namespace, 212 | * replacing any others previously set for this namespace. 213 | * 214 | * @param string $prefix The prefix/namespace, with trailing '\\' 215 | * @param array|string $paths The PSR-4 base directories 216 | * 217 | * @throws \InvalidArgumentException 218 | */ 219 | public function setPsr4($prefix, $paths) 220 | { 221 | if (!$prefix) { 222 | $this->fallbackDirsPsr4 = (array) $paths; 223 | } else { 224 | $length = strlen($prefix); 225 | if ('\\' !== $prefix[$length - 1]) { 226 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 227 | } 228 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 229 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 230 | } 231 | } 232 | 233 | /** 234 | * Turns on searching the include path for class files. 235 | * 236 | * @param bool $useIncludePath 237 | */ 238 | public function setUseIncludePath($useIncludePath) 239 | { 240 | $this->useIncludePath = $useIncludePath; 241 | } 242 | 243 | /** 244 | * Can be used to check if the autoloader uses the include path to check 245 | * for classes. 246 | * 247 | * @return bool 248 | */ 249 | public function getUseIncludePath() 250 | { 251 | return $this->useIncludePath; 252 | } 253 | 254 | /** 255 | * Turns off searching the prefix and fallback directories for classes 256 | * that have not been registered with the class map. 257 | * 258 | * @param bool $classMapAuthoritative 259 | */ 260 | public function setClassMapAuthoritative($classMapAuthoritative) 261 | { 262 | $this->classMapAuthoritative = $classMapAuthoritative; 263 | } 264 | 265 | /** 266 | * Should class lookup fail if not found in the current class map? 267 | * 268 | * @return bool 269 | */ 270 | public function isClassMapAuthoritative() 271 | { 272 | return $this->classMapAuthoritative; 273 | } 274 | 275 | /** 276 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled. 277 | * 278 | * @param string|null $apcuPrefix 279 | */ 280 | public function setApcuPrefix($apcuPrefix) 281 | { 282 | $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; 283 | } 284 | 285 | /** 286 | * The APCu prefix in use, or null if APCu caching is not enabled. 287 | * 288 | * @return string|null 289 | */ 290 | public function getApcuPrefix() 291 | { 292 | return $this->apcuPrefix; 293 | } 294 | 295 | /** 296 | * Registers this instance as an autoloader. 297 | * 298 | * @param bool $prepend Whether to prepend the autoloader or not 299 | */ 300 | public function register($prepend = false) 301 | { 302 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); 303 | } 304 | 305 | /** 306 | * Unregisters this instance as an autoloader. 307 | */ 308 | public function unregister() 309 | { 310 | spl_autoload_unregister(array($this, 'loadClass')); 311 | } 312 | 313 | /** 314 | * Loads the given class or interface. 315 | * 316 | * @param string $class The name of the class 317 | * @return bool|null True if loaded, null otherwise 318 | */ 319 | public function loadClass($class) 320 | { 321 | if ($file = $this->findFile($class)) { 322 | includeFile($file); 323 | 324 | return true; 325 | } 326 | } 327 | 328 | /** 329 | * Finds the path to the file where the class is defined. 330 | * 331 | * @param string $class The name of the class 332 | * 333 | * @return string|false The path if found, false otherwise 334 | */ 335 | public function findFile($class) 336 | { 337 | // class map lookup 338 | if (isset($this->classMap[$class])) { 339 | return $this->classMap[$class]; 340 | } 341 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { 342 | return false; 343 | } 344 | if (null !== $this->apcuPrefix) { 345 | $file = apcu_fetch($this->apcuPrefix.$class, $hit); 346 | if ($hit) { 347 | return $file; 348 | } 349 | } 350 | 351 | $file = $this->findFileWithExtension($class, '.php'); 352 | 353 | // Search for Hack files if we are running on HHVM 354 | if (false === $file && defined('HHVM_VERSION')) { 355 | $file = $this->findFileWithExtension($class, '.hh'); 356 | } 357 | 358 | if (null !== $this->apcuPrefix) { 359 | apcu_add($this->apcuPrefix.$class, $file); 360 | } 361 | 362 | if (false === $file) { 363 | // Remember that this class does not exist. 364 | $this->missingClasses[$class] = true; 365 | } 366 | 367 | return $file; 368 | } 369 | 370 | private function findFileWithExtension($class, $ext) 371 | { 372 | // PSR-4 lookup 373 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; 374 | 375 | $first = $class[0]; 376 | if (isset($this->prefixLengthsPsr4[$first])) { 377 | $subPath = $class; 378 | while (false !== $lastPos = strrpos($subPath, '\\')) { 379 | $subPath = substr($subPath, 0, $lastPos); 380 | $search = $subPath . '\\'; 381 | if (isset($this->prefixDirsPsr4[$search])) { 382 | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); 383 | foreach ($this->prefixDirsPsr4[$search] as $dir) { 384 | if (file_exists($file = $dir . $pathEnd)) { 385 | return $file; 386 | } 387 | } 388 | } 389 | } 390 | } 391 | 392 | // PSR-4 fallback dirs 393 | foreach ($this->fallbackDirsPsr4 as $dir) { 394 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { 395 | return $file; 396 | } 397 | } 398 | 399 | // PSR-0 lookup 400 | if (false !== $pos = strrpos($class, '\\')) { 401 | // namespaced class name 402 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) 403 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); 404 | } else { 405 | // PEAR-like class name 406 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; 407 | } 408 | 409 | if (isset($this->prefixesPsr0[$first])) { 410 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { 411 | if (0 === strpos($class, $prefix)) { 412 | foreach ($dirs as $dir) { 413 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 414 | return $file; 415 | } 416 | } 417 | } 418 | } 419 | } 420 | 421 | // PSR-0 fallback dirs 422 | foreach ($this->fallbackDirsPsr0 as $dir) { 423 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 424 | return $file; 425 | } 426 | } 427 | 428 | // PSR-0 include paths. 429 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { 430 | return $file; 431 | } 432 | 433 | return false; 434 | } 435 | } 436 | 437 | /** 438 | * Scope isolated include. 439 | * 440 | * Prevents access to $this/self from included files. 441 | */ 442 | function includeFile($file) 443 | { 444 | include $file; 445 | } 446 | -------------------------------------------------------------------------------- /vendor/joetannenbaum/alfred-workflow/tests/WorkflowTest.php: -------------------------------------------------------------------------------- 1 | result() 13 | ->uid('THE ID') 14 | ->title('Item Title') 15 | ->subtitle('Item Subtitle') 16 | ->quicklookurl('https://www.google.com') 17 | ->type('file') 18 | ->arg('ARGUMENT') 19 | ->valid(false) 20 | ->icon('icon.png') 21 | ->mod('cmd', 'Do Something Different', 'something-different') 22 | ->mod('shift', 'Another Different', 'another-different', false) 23 | ->copy('Please copy this') 24 | ->largetype('This will be huge') 25 | ->autocomplete('AutoComplete This'); 26 | 27 | $expected = [ 28 | 'items' => [ 29 | [ 30 | 'arg' => 'ARGUMENT', 31 | 'autocomplete' => 'AutoComplete This', 32 | 'icon' => [ 33 | 'path' => 'icon.png', 34 | ], 35 | 'mods' => [ 36 | 'cmd' => [ 37 | 'subtitle' => 'Do Something Different', 38 | 'arg' => 'something-different', 39 | 'valid' => true, 40 | ], 41 | 'shift' => [ 42 | 'subtitle' => 'Another Different', 43 | 'arg' => 'another-different', 44 | 'valid' => false, 45 | ], 46 | ], 47 | 'quicklookurl' => 'https://www.google.com', 48 | 'subtitle' => 'Item Subtitle', 49 | 'text' => [ 50 | 'copy' => 'Please copy this', 51 | 'largetype' => 'This will be huge', 52 | ], 53 | 'title' => 'Item Title', 54 | 'type' => 'file', 55 | 'uid' => 'THE ID', 56 | 'valid' => false, 57 | ], 58 | ], 59 | ]; 60 | 61 | $this->assertSame(json_encode($expected), $workflow->output()); 62 | } 63 | 64 | /** @test */ 65 | public function it_can_add_multiple_results() 66 | { 67 | $workflow = new Workflow; 68 | 69 | $workflow->result() 70 | ->uid('THE ID') 71 | ->title('Item Title') 72 | ->subtitle('Item Subtitle') 73 | ->quicklookurl('https://www.google.com') 74 | ->type('file') 75 | ->arg('ARGUMENT') 76 | ->valid(false) 77 | ->icon('icon.png') 78 | ->mod('cmd', 'Do Something Different', 'something-different') 79 | ->mod('shift', 'Another Different', 'another-different', false) 80 | ->copy('Please copy this') 81 | ->largetype('This will be huge') 82 | ->autocomplete('AutoComplete This'); 83 | 84 | $workflow->result() 85 | ->uid('THE ID 2') 86 | ->title('Item Title 2') 87 | ->subtitle('Item Subtitle 2') 88 | ->quicklookurl('https://www.google.com/2') 89 | ->type('file') 90 | ->arg('ARGUMENT 2') 91 | ->valid(true) 92 | ->icon('icon2.png') 93 | ->mod('cmd', 'Do Something Different 2', 'something-different 2') 94 | ->mod('shift', 'Another Different 2', 'another-different 2', false) 95 | ->copy('Please copy this 2') 96 | ->largetype('This will be huge 2') 97 | ->autocomplete('AutoComplete This 2'); 98 | 99 | $expected = [ 100 | 'items' => [ 101 | [ 102 | 'arg' => 'ARGUMENT', 103 | 'autocomplete' => 'AutoComplete This', 104 | 'icon' => [ 105 | 'path' => 'icon.png', 106 | ], 107 | 'mods' => [ 108 | 'cmd' => [ 109 | 'subtitle' => 'Do Something Different', 110 | 'arg' => 'something-different', 111 | 'valid' => true, 112 | ], 113 | 'shift' => [ 114 | 'subtitle' => 'Another Different', 115 | 'arg' => 'another-different', 116 | 'valid' => false, 117 | ], 118 | ], 119 | 'quicklookurl' => 'https://www.google.com', 120 | 'subtitle' => 'Item Subtitle', 121 | 'text' => [ 122 | 'copy' => 'Please copy this', 123 | 'largetype' => 'This will be huge', 124 | ], 125 | 'title' => 'Item Title', 126 | 'type' => 'file', 127 | 'uid' => 'THE ID', 128 | 'valid' => false, 129 | ], 130 | [ 131 | 'arg' => 'ARGUMENT 2', 132 | 'autocomplete' => 'AutoComplete This 2', 133 | 'icon' => [ 134 | 'path' => 'icon2.png', 135 | ], 136 | 'mods' => [ 137 | 'cmd' => [ 138 | 'subtitle' => 'Do Something Different 2', 139 | 'arg' => 'something-different 2', 140 | 'valid' => true, 141 | ], 142 | 'shift' => [ 143 | 'subtitle' => 'Another Different 2', 144 | 'arg' => 'another-different 2', 145 | 'valid' => false, 146 | ], 147 | ], 148 | 'quicklookurl' => 'https://www.google.com/2', 149 | 'subtitle' => 'Item Subtitle 2', 150 | 'text' => [ 151 | 'copy' => 'Please copy this 2', 152 | 'largetype' => 'This will be huge 2', 153 | ], 154 | 'title' => 'Item Title 2', 155 | 'type' => 'file', 156 | 'uid' => 'THE ID 2', 157 | 'valid' => true, 158 | ], 159 | ], 160 | ]; 161 | 162 | $this->assertSame(json_encode($expected), $workflow->output()); 163 | } 164 | 165 | /** @test */ 166 | public function it_can_handle_a_file_skipcheck_via_arguments() 167 | { 168 | $workflow = new Workflow; 169 | 170 | $workflow->result()->type('file', false); 171 | 172 | $expected = [ 173 | 'items' => [ 174 | [ 175 | 'type' => 'file:skipcheck', 176 | 'valid' => true, 177 | ], 178 | ], 179 | ]; 180 | 181 | $this->assertSame(json_encode($expected), $workflow->output()); 182 | } 183 | 184 | /** @test */ 185 | public function it_can_add_mods_via_shortcuts() 186 | { 187 | $workflow = new Workflow; 188 | 189 | $workflow->result()->cmd('Hit Command', 'command-it', false) 190 | ->shift('Hit Shift', 'shift-it', true); 191 | 192 | $expected = [ 193 | 'items' => [ 194 | [ 195 | 'mods' => [ 196 | 'cmd' => [ 197 | 'subtitle' => 'Hit Command', 198 | 'arg' => 'command-it', 199 | 'valid' => false, 200 | ], 201 | 'shift' => [ 202 | 'subtitle' => 'Hit Shift', 203 | 'arg' => 'shift-it', 204 | 'valid' => true, 205 | ], 206 | ], 207 | 'valid' => true, 208 | ], 209 | ], 210 | ]; 211 | 212 | $this->assertSame(json_encode($expected), $workflow->output()); 213 | } 214 | 215 | /** @test */ 216 | public function it_can_handle_file_icon_via_shortcut() 217 | { 218 | $workflow = new Workflow; 219 | 220 | $workflow->result()->fileiconIcon('icon.png'); 221 | 222 | $expected = [ 223 | 'items' => [ 224 | [ 225 | 'icon' => [ 226 | 'path' => 'icon.png', 227 | 'type' => 'fileicon', 228 | ], 229 | 'valid' => true, 230 | ], 231 | ], 232 | ]; 233 | 234 | $this->assertSame(json_encode($expected), $workflow->output()); 235 | } 236 | 237 | /** @test */ 238 | public function it_can_handle_file_type_via_shortcut() 239 | { 240 | $workflow = new Workflow; 241 | 242 | $workflow->result()->filetypeIcon('icon.png'); 243 | 244 | $expected = [ 245 | 'items' => [ 246 | [ 247 | 'icon' => [ 248 | 'path' => 'icon.png', 249 | 'type' => 'filetype', 250 | ], 251 | 'valid' => true, 252 | ], 253 | ], 254 | ]; 255 | 256 | $this->assertSame(json_encode($expected), $workflow->output()); 257 | } 258 | 259 | /** @test */ 260 | public function it_can_sort_results_by_defaults() 261 | { 262 | $workflow = new Workflow; 263 | 264 | $workflow->result() 265 | ->uid('THE ID') 266 | ->title('Item Title') 267 | ->subtitle('Item Subtitle'); 268 | 269 | $workflow->result() 270 | ->uid('THE ID 2') 271 | ->title('Item Title 2') 272 | ->subtitle('Item Subtitle 2'); 273 | 274 | $expected = [ 275 | 'items' => [ 276 | [ 277 | 'subtitle' => 'Item Subtitle', 278 | 'title' => 'Item Title', 279 | 'uid' => 'THE ID', 280 | 'valid' => true, 281 | ], 282 | [ 283 | 'subtitle' => 'Item Subtitle 2', 284 | 'title' => 'Item Title 2', 285 | 'uid' => 'THE ID 2', 286 | 'valid' => true, 287 | ], 288 | ], 289 | ]; 290 | 291 | $this->assertSame(json_encode($expected), $workflow->sortResults()->output()); 292 | } 293 | 294 | /** @test */ 295 | public function it_can_sort_results_desc() 296 | { 297 | $workflow = new Workflow; 298 | 299 | $workflow->result() 300 | ->uid('THE ID') 301 | ->title('Item Title') 302 | ->subtitle('Item Subtitle'); 303 | 304 | $workflow->result() 305 | ->uid('THE ID 2') 306 | ->title('Item Title 2') 307 | ->subtitle('Item Subtitle 2'); 308 | 309 | $expected = [ 310 | 'items' => [ 311 | [ 312 | 'subtitle' => 'Item Subtitle 2', 313 | 'title' => 'Item Title 2', 314 | 'uid' => 'THE ID 2', 315 | 'valid' => true, 316 | ], 317 | [ 318 | 'subtitle' => 'Item Subtitle', 319 | 'title' => 'Item Title', 320 | 'uid' => 'THE ID', 321 | 'valid' => true, 322 | ], 323 | ], 324 | ]; 325 | 326 | $this->assertSame(json_encode($expected), $workflow->sortResults('desc')->output()); 327 | } 328 | 329 | /** @test */ 330 | public function it_can_sort_results_by_field() 331 | { 332 | $workflow = new Workflow; 333 | 334 | $workflow->result() 335 | ->uid('456') 336 | ->title('Item Title') 337 | ->subtitle('Item Subtitle'); 338 | 339 | $workflow->result() 340 | ->uid('123') 341 | ->title('Item Title 2') 342 | ->subtitle('Item Subtitle 2'); 343 | 344 | $expected = [ 345 | 'items' => [ 346 | [ 347 | 'subtitle' => 'Item Subtitle 2', 348 | 'title' => 'Item Title 2', 349 | 'uid' => '123', 350 | 'valid' => true, 351 | ], 352 | [ 353 | 'subtitle' => 'Item Subtitle', 354 | 'title' => 'Item Title', 355 | 'uid' => '456', 356 | 'valid' => true, 357 | ], 358 | ], 359 | ]; 360 | 361 | $this->assertSame(json_encode($expected), $workflow->sortResults('asc', 'uid')->output()); 362 | } 363 | 364 | /** @test */ 365 | public function it_can_filter_results() 366 | { 367 | $workflow = new Workflow; 368 | 369 | $workflow->result() 370 | ->uid('THE ID') 371 | ->title('Item Title') 372 | ->subtitle('Item Subtitle'); 373 | 374 | $workflow->result() 375 | ->uid('THE ID 2') 376 | ->title('Item Title 2') 377 | ->subtitle('Item Subtitle 2'); 378 | 379 | $expected = [ 380 | 'items' => [ 381 | [ 382 | 'subtitle' => 'Item Subtitle 2', 383 | 'title' => 'Item Title 2', 384 | 'uid' => 'THE ID 2', 385 | 'valid' => true, 386 | ], 387 | ], 388 | ]; 389 | 390 | $this->assertSame(json_encode($expected), $workflow->filterResults(2)->output()); 391 | } 392 | 393 | /** @test */ 394 | public function it_can_filter_results_by_a_different_key() 395 | { 396 | $workflow = new Workflow; 397 | 398 | $workflow->result() 399 | ->uid('THE ID') 400 | ->title('Item Title') 401 | ->subtitle('Item Subtitle'); 402 | 403 | $workflow->result() 404 | ->uid('THE ID 2') 405 | ->title('Item Title 2') 406 | ->subtitle('Item Subtitle 2'); 407 | 408 | $expected = [ 409 | 'items' => [ 410 | [ 411 | 'subtitle' => 'Item Subtitle 2', 412 | 'title' => 'Item Title 2', 413 | 'uid' => 'THE ID 2', 414 | 'valid' => true, 415 | ], 416 | ], 417 | ]; 418 | 419 | $this->assertSame(json_encode($expected), $workflow->filterResults('ID 2', 'uid')->output()); 420 | } 421 | 422 | /** @test */ 423 | public function it_can_add_variables() 424 | { 425 | $workflow = new Workflow; 426 | 427 | $workflow->variable('fruit','apple') 428 | ->variable('vegetables','carrots'); 429 | 430 | $workflow->result() 431 | ->uid('THE ID') 432 | ->title('Item Title') 433 | ->subtitle('Item Subtitle') 434 | ->quicklookurl('https://www.google.com') 435 | ->type('file') 436 | ->arg('ARGUMENT') 437 | ->valid(false) 438 | ->icon('icon.png') 439 | ->mod('cmd', 'Do Something Different', 'something-different') 440 | ->mod('shift', 'Another Different', 'another-different', false) 441 | ->copy('Please copy this') 442 | ->largetype('This will be huge') 443 | ->autocomplete('AutoComplete This'); 444 | 445 | $expected = [ 446 | 'items' => [ 447 | [ 448 | 'arg' => 'ARGUMENT', 449 | 'autocomplete' => 'AutoComplete This', 450 | 'icon' => [ 451 | 'path' => 'icon.png', 452 | ], 453 | 'mods' => [ 454 | 'cmd' => [ 455 | 'subtitle' => 'Do Something Different', 456 | 'arg' => 'something-different', 457 | 'valid' => true, 458 | ], 459 | 'shift' => [ 460 | 'subtitle' => 'Another Different', 461 | 'arg' => 'another-different', 462 | 'valid' => false, 463 | ], 464 | ], 465 | 'quicklookurl' => 'https://www.google.com', 466 | 'subtitle' => 'Item Subtitle', 467 | 'text' => [ 468 | 'copy' => 'Please copy this', 469 | 'largetype' => 'This will be huge', 470 | ], 471 | 'title' => 'Item Title', 472 | 'type' => 'file', 473 | 'uid' => 'THE ID', 474 | 'valid' => false, 475 | ], 476 | ], 477 | 'variables' => [ 478 | 'fruit' => 'apple', 479 | 'vegetables' => 'carrots' 480 | ] 481 | ]; 482 | 483 | $this->assertSame(json_encode($expected), $workflow->output()); 484 | } 485 | } 486 | -------------------------------------------------------------------------------- /vendor/joetannenbaum/alfred-workflow/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": "86d8b89e2e3aec5dbb790f43ac8c1169", 8 | "content-hash": "b3abb59d86e4ce2ad1f9368fd77f65c9", 9 | "packages": [], 10 | "packages-dev": [ 11 | { 12 | "name": "doctrine/instantiator", 13 | "version": "1.0.5", 14 | "source": { 15 | "type": "git", 16 | "url": "https://github.com/doctrine/instantiator.git", 17 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" 18 | }, 19 | "dist": { 20 | "type": "zip", 21 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", 22 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", 23 | "shasum": "" 24 | }, 25 | "require": { 26 | "php": ">=5.3,<8.0-DEV" 27 | }, 28 | "require-dev": { 29 | "athletic/athletic": "~0.1.8", 30 | "ext-pdo": "*", 31 | "ext-phar": "*", 32 | "phpunit/phpunit": "~4.0", 33 | "squizlabs/php_codesniffer": "~2.0" 34 | }, 35 | "type": "library", 36 | "extra": { 37 | "branch-alias": { 38 | "dev-master": "1.0.x-dev" 39 | } 40 | }, 41 | "autoload": { 42 | "psr-4": { 43 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 44 | } 45 | }, 46 | "notification-url": "https://packagist.org/downloads/", 47 | "license": [ 48 | "MIT" 49 | ], 50 | "authors": [ 51 | { 52 | "name": "Marco Pivetta", 53 | "email": "ocramius@gmail.com", 54 | "homepage": "http://ocramius.github.com/" 55 | } 56 | ], 57 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 58 | "homepage": "https://github.com/doctrine/instantiator", 59 | "keywords": [ 60 | "constructor", 61 | "instantiate" 62 | ], 63 | "time": "2015-06-14 21:17:01" 64 | }, 65 | { 66 | "name": "myclabs/deep-copy", 67 | "version": "1.5.1", 68 | "source": { 69 | "type": "git", 70 | "url": "https://github.com/myclabs/DeepCopy.git", 71 | "reference": "a8773992b362b58498eed24bf85005f363c34771" 72 | }, 73 | "dist": { 74 | "type": "zip", 75 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/a8773992b362b58498eed24bf85005f363c34771", 76 | "reference": "a8773992b362b58498eed24bf85005f363c34771", 77 | "shasum": "" 78 | }, 79 | "require": { 80 | "php": ">=5.4.0" 81 | }, 82 | "require-dev": { 83 | "doctrine/collections": "1.*", 84 | "phpunit/phpunit": "~4.1" 85 | }, 86 | "type": "library", 87 | "autoload": { 88 | "psr-4": { 89 | "DeepCopy\\": "src/DeepCopy/" 90 | } 91 | }, 92 | "notification-url": "https://packagist.org/downloads/", 93 | "license": [ 94 | "MIT" 95 | ], 96 | "description": "Create deep copies (clones) of your objects", 97 | "homepage": "https://github.com/myclabs/DeepCopy", 98 | "keywords": [ 99 | "clone", 100 | "copy", 101 | "duplicate", 102 | "object", 103 | "object graph" 104 | ], 105 | "time": "2015-11-20 12:04:31" 106 | }, 107 | { 108 | "name": "phpdocumentor/reflection-docblock", 109 | "version": "2.0.4", 110 | "source": { 111 | "type": "git", 112 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 113 | "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" 114 | }, 115 | "dist": { 116 | "type": "zip", 117 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", 118 | "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", 119 | "shasum": "" 120 | }, 121 | "require": { 122 | "php": ">=5.3.3" 123 | }, 124 | "require-dev": { 125 | "phpunit/phpunit": "~4.0" 126 | }, 127 | "suggest": { 128 | "dflydev/markdown": "~1.0", 129 | "erusev/parsedown": "~1.0" 130 | }, 131 | "type": "library", 132 | "extra": { 133 | "branch-alias": { 134 | "dev-master": "2.0.x-dev" 135 | } 136 | }, 137 | "autoload": { 138 | "psr-0": { 139 | "phpDocumentor": [ 140 | "src/" 141 | ] 142 | } 143 | }, 144 | "notification-url": "https://packagist.org/downloads/", 145 | "license": [ 146 | "MIT" 147 | ], 148 | "authors": [ 149 | { 150 | "name": "Mike van Riel", 151 | "email": "mike.vanriel@naenius.com" 152 | } 153 | ], 154 | "time": "2015-02-03 12:10:50" 155 | }, 156 | { 157 | "name": "phpspec/prophecy", 158 | "version": "v1.6.0", 159 | "source": { 160 | "type": "git", 161 | "url": "https://github.com/phpspec/prophecy.git", 162 | "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972" 163 | }, 164 | "dist": { 165 | "type": "zip", 166 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972", 167 | "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972", 168 | "shasum": "" 169 | }, 170 | "require": { 171 | "doctrine/instantiator": "^1.0.2", 172 | "php": "^5.3|^7.0", 173 | "phpdocumentor/reflection-docblock": "~2.0", 174 | "sebastian/comparator": "~1.1", 175 | "sebastian/recursion-context": "~1.0" 176 | }, 177 | "require-dev": { 178 | "phpspec/phpspec": "~2.0" 179 | }, 180 | "type": "library", 181 | "extra": { 182 | "branch-alias": { 183 | "dev-master": "1.5.x-dev" 184 | } 185 | }, 186 | "autoload": { 187 | "psr-0": { 188 | "Prophecy\\": "src/" 189 | } 190 | }, 191 | "notification-url": "https://packagist.org/downloads/", 192 | "license": [ 193 | "MIT" 194 | ], 195 | "authors": [ 196 | { 197 | "name": "Konstantin Kudryashov", 198 | "email": "ever.zet@gmail.com", 199 | "homepage": "http://everzet.com" 200 | }, 201 | { 202 | "name": "Marcello Duarte", 203 | "email": "marcello.duarte@gmail.com" 204 | } 205 | ], 206 | "description": "Highly opinionated mocking framework for PHP 5.3+", 207 | "homepage": "https://github.com/phpspec/prophecy", 208 | "keywords": [ 209 | "Double", 210 | "Dummy", 211 | "fake", 212 | "mock", 213 | "spy", 214 | "stub" 215 | ], 216 | "time": "2016-02-15 07:46:21" 217 | }, 218 | { 219 | "name": "phpunit/php-code-coverage", 220 | "version": "3.3.1", 221 | "source": { 222 | "type": "git", 223 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 224 | "reference": "2431befdd451fac43fbcde94d1a92fb3b8b68f86" 225 | }, 226 | "dist": { 227 | "type": "zip", 228 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2431befdd451fac43fbcde94d1a92fb3b8b68f86", 229 | "reference": "2431befdd451fac43fbcde94d1a92fb3b8b68f86", 230 | "shasum": "" 231 | }, 232 | "require": { 233 | "php": "^5.6 || ^7.0", 234 | "phpunit/php-file-iterator": "~1.3", 235 | "phpunit/php-text-template": "~1.2", 236 | "phpunit/php-token-stream": "^1.4.2", 237 | "sebastian/code-unit-reverse-lookup": "~1.0", 238 | "sebastian/environment": "^1.3.2", 239 | "sebastian/version": "~1.0|~2.0" 240 | }, 241 | "require-dev": { 242 | "ext-xdebug": ">=2.1.4", 243 | "phpunit/phpunit": "~5" 244 | }, 245 | "suggest": { 246 | "ext-dom": "*", 247 | "ext-xdebug": ">=2.4.0", 248 | "ext-xmlwriter": "*" 249 | }, 250 | "type": "library", 251 | "extra": { 252 | "branch-alias": { 253 | "dev-master": "3.3.x-dev" 254 | } 255 | }, 256 | "autoload": { 257 | "classmap": [ 258 | "src/" 259 | ] 260 | }, 261 | "notification-url": "https://packagist.org/downloads/", 262 | "license": [ 263 | "BSD-3-Clause" 264 | ], 265 | "authors": [ 266 | { 267 | "name": "Sebastian Bergmann", 268 | "email": "sb@sebastian-bergmann.de", 269 | "role": "lead" 270 | } 271 | ], 272 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 273 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 274 | "keywords": [ 275 | "coverage", 276 | "testing", 277 | "xunit" 278 | ], 279 | "time": "2016-04-08 08:14:53" 280 | }, 281 | { 282 | "name": "phpunit/php-file-iterator", 283 | "version": "1.4.1", 284 | "source": { 285 | "type": "git", 286 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 287 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" 288 | }, 289 | "dist": { 290 | "type": "zip", 291 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", 292 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", 293 | "shasum": "" 294 | }, 295 | "require": { 296 | "php": ">=5.3.3" 297 | }, 298 | "type": "library", 299 | "extra": { 300 | "branch-alias": { 301 | "dev-master": "1.4.x-dev" 302 | } 303 | }, 304 | "autoload": { 305 | "classmap": [ 306 | "src/" 307 | ] 308 | }, 309 | "notification-url": "https://packagist.org/downloads/", 310 | "license": [ 311 | "BSD-3-Clause" 312 | ], 313 | "authors": [ 314 | { 315 | "name": "Sebastian Bergmann", 316 | "email": "sb@sebastian-bergmann.de", 317 | "role": "lead" 318 | } 319 | ], 320 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 321 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 322 | "keywords": [ 323 | "filesystem", 324 | "iterator" 325 | ], 326 | "time": "2015-06-21 13:08:43" 327 | }, 328 | { 329 | "name": "phpunit/php-text-template", 330 | "version": "1.2.1", 331 | "source": { 332 | "type": "git", 333 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 334 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 335 | }, 336 | "dist": { 337 | "type": "zip", 338 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 339 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 340 | "shasum": "" 341 | }, 342 | "require": { 343 | "php": ">=5.3.3" 344 | }, 345 | "type": "library", 346 | "autoload": { 347 | "classmap": [ 348 | "src/" 349 | ] 350 | }, 351 | "notification-url": "https://packagist.org/downloads/", 352 | "license": [ 353 | "BSD-3-Clause" 354 | ], 355 | "authors": [ 356 | { 357 | "name": "Sebastian Bergmann", 358 | "email": "sebastian@phpunit.de", 359 | "role": "lead" 360 | } 361 | ], 362 | "description": "Simple template engine.", 363 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 364 | "keywords": [ 365 | "template" 366 | ], 367 | "time": "2015-06-21 13:50:34" 368 | }, 369 | { 370 | "name": "phpunit/php-timer", 371 | "version": "1.0.8", 372 | "source": { 373 | "type": "git", 374 | "url": "https://github.com/sebastianbergmann/php-timer.git", 375 | "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" 376 | }, 377 | "dist": { 378 | "type": "zip", 379 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", 380 | "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", 381 | "shasum": "" 382 | }, 383 | "require": { 384 | "php": ">=5.3.3" 385 | }, 386 | "require-dev": { 387 | "phpunit/phpunit": "~4|~5" 388 | }, 389 | "type": "library", 390 | "autoload": { 391 | "classmap": [ 392 | "src/" 393 | ] 394 | }, 395 | "notification-url": "https://packagist.org/downloads/", 396 | "license": [ 397 | "BSD-3-Clause" 398 | ], 399 | "authors": [ 400 | { 401 | "name": "Sebastian Bergmann", 402 | "email": "sb@sebastian-bergmann.de", 403 | "role": "lead" 404 | } 405 | ], 406 | "description": "Utility class for timing", 407 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 408 | "keywords": [ 409 | "timer" 410 | ], 411 | "time": "2016-05-12 18:03:57" 412 | }, 413 | { 414 | "name": "phpunit/php-token-stream", 415 | "version": "1.4.8", 416 | "source": { 417 | "type": "git", 418 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 419 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" 420 | }, 421 | "dist": { 422 | "type": "zip", 423 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", 424 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", 425 | "shasum": "" 426 | }, 427 | "require": { 428 | "ext-tokenizer": "*", 429 | "php": ">=5.3.3" 430 | }, 431 | "require-dev": { 432 | "phpunit/phpunit": "~4.2" 433 | }, 434 | "type": "library", 435 | "extra": { 436 | "branch-alias": { 437 | "dev-master": "1.4-dev" 438 | } 439 | }, 440 | "autoload": { 441 | "classmap": [ 442 | "src/" 443 | ] 444 | }, 445 | "notification-url": "https://packagist.org/downloads/", 446 | "license": [ 447 | "BSD-3-Clause" 448 | ], 449 | "authors": [ 450 | { 451 | "name": "Sebastian Bergmann", 452 | "email": "sebastian@phpunit.de" 453 | } 454 | ], 455 | "description": "Wrapper around PHP's tokenizer extension.", 456 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 457 | "keywords": [ 458 | "tokenizer" 459 | ], 460 | "time": "2015-09-15 10:49:45" 461 | }, 462 | { 463 | "name": "phpunit/phpunit", 464 | "version": "5.3.4", 465 | "source": { 466 | "type": "git", 467 | "url": "https://github.com/sebastianbergmann/phpunit.git", 468 | "reference": "00dd95ffb48805503817ced06399017df315fe5c" 469 | }, 470 | "dist": { 471 | "type": "zip", 472 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/00dd95ffb48805503817ced06399017df315fe5c", 473 | "reference": "00dd95ffb48805503817ced06399017df315fe5c", 474 | "shasum": "" 475 | }, 476 | "require": { 477 | "ext-dom": "*", 478 | "ext-json": "*", 479 | "ext-pcre": "*", 480 | "ext-reflection": "*", 481 | "ext-spl": "*", 482 | "myclabs/deep-copy": "~1.3", 483 | "php": "^5.6 || ^7.0", 484 | "phpspec/prophecy": "^1.3.1", 485 | "phpunit/php-code-coverage": "^3.3.0", 486 | "phpunit/php-file-iterator": "~1.4", 487 | "phpunit/php-text-template": "~1.2", 488 | "phpunit/php-timer": "^1.0.6", 489 | "phpunit/phpunit-mock-objects": "^3.1", 490 | "sebastian/comparator": "~1.1", 491 | "sebastian/diff": "~1.2", 492 | "sebastian/environment": "~1.3", 493 | "sebastian/exporter": "~1.2", 494 | "sebastian/global-state": "~1.0", 495 | "sebastian/object-enumerator": "~1.0", 496 | "sebastian/resource-operations": "~1.0", 497 | "sebastian/version": "~1.0|~2.0", 498 | "symfony/yaml": "~2.1|~3.0" 499 | }, 500 | "suggest": { 501 | "phpunit/php-invoker": "~1.1" 502 | }, 503 | "bin": [ 504 | "phpunit" 505 | ], 506 | "type": "library", 507 | "extra": { 508 | "branch-alias": { 509 | "dev-master": "5.3.x-dev" 510 | } 511 | }, 512 | "autoload": { 513 | "classmap": [ 514 | "src/" 515 | ] 516 | }, 517 | "notification-url": "https://packagist.org/downloads/", 518 | "license": [ 519 | "BSD-3-Clause" 520 | ], 521 | "authors": [ 522 | { 523 | "name": "Sebastian Bergmann", 524 | "email": "sebastian@phpunit.de", 525 | "role": "lead" 526 | } 527 | ], 528 | "description": "The PHP Unit Testing framework.", 529 | "homepage": "https://phpunit.de/", 530 | "keywords": [ 531 | "phpunit", 532 | "testing", 533 | "xunit" 534 | ], 535 | "time": "2016-05-11 13:28:45" 536 | }, 537 | { 538 | "name": "phpunit/phpunit-mock-objects", 539 | "version": "3.1.3", 540 | "source": { 541 | "type": "git", 542 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 543 | "reference": "151c96874bff6fe61a25039df60e776613a61489" 544 | }, 545 | "dist": { 546 | "type": "zip", 547 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/151c96874bff6fe61a25039df60e776613a61489", 548 | "reference": "151c96874bff6fe61a25039df60e776613a61489", 549 | "shasum": "" 550 | }, 551 | "require": { 552 | "doctrine/instantiator": "^1.0.2", 553 | "php": ">=5.6", 554 | "phpunit/php-text-template": "~1.2", 555 | "sebastian/exporter": "~1.2" 556 | }, 557 | "require-dev": { 558 | "phpunit/phpunit": "~5" 559 | }, 560 | "suggest": { 561 | "ext-soap": "*" 562 | }, 563 | "type": "library", 564 | "extra": { 565 | "branch-alias": { 566 | "dev-master": "3.1.x-dev" 567 | } 568 | }, 569 | "autoload": { 570 | "classmap": [ 571 | "src/" 572 | ] 573 | }, 574 | "notification-url": "https://packagist.org/downloads/", 575 | "license": [ 576 | "BSD-3-Clause" 577 | ], 578 | "authors": [ 579 | { 580 | "name": "Sebastian Bergmann", 581 | "email": "sb@sebastian-bergmann.de", 582 | "role": "lead" 583 | } 584 | ], 585 | "description": "Mock Object library for PHPUnit", 586 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 587 | "keywords": [ 588 | "mock", 589 | "xunit" 590 | ], 591 | "time": "2016-04-20 14:39:26" 592 | }, 593 | { 594 | "name": "sebastian/code-unit-reverse-lookup", 595 | "version": "1.0.0", 596 | "source": { 597 | "type": "git", 598 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 599 | "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe" 600 | }, 601 | "dist": { 602 | "type": "zip", 603 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe", 604 | "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe", 605 | "shasum": "" 606 | }, 607 | "require": { 608 | "php": ">=5.6" 609 | }, 610 | "require-dev": { 611 | "phpunit/phpunit": "~5" 612 | }, 613 | "type": "library", 614 | "extra": { 615 | "branch-alias": { 616 | "dev-master": "1.0.x-dev" 617 | } 618 | }, 619 | "autoload": { 620 | "classmap": [ 621 | "src/" 622 | ] 623 | }, 624 | "notification-url": "https://packagist.org/downloads/", 625 | "license": [ 626 | "BSD-3-Clause" 627 | ], 628 | "authors": [ 629 | { 630 | "name": "Sebastian Bergmann", 631 | "email": "sebastian@phpunit.de" 632 | } 633 | ], 634 | "description": "Looks up which function or method a line of code belongs to", 635 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 636 | "time": "2016-02-13 06:45:14" 637 | }, 638 | { 639 | "name": "sebastian/comparator", 640 | "version": "1.2.0", 641 | "source": { 642 | "type": "git", 643 | "url": "https://github.com/sebastianbergmann/comparator.git", 644 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" 645 | }, 646 | "dist": { 647 | "type": "zip", 648 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", 649 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", 650 | "shasum": "" 651 | }, 652 | "require": { 653 | "php": ">=5.3.3", 654 | "sebastian/diff": "~1.2", 655 | "sebastian/exporter": "~1.2" 656 | }, 657 | "require-dev": { 658 | "phpunit/phpunit": "~4.4" 659 | }, 660 | "type": "library", 661 | "extra": { 662 | "branch-alias": { 663 | "dev-master": "1.2.x-dev" 664 | } 665 | }, 666 | "autoload": { 667 | "classmap": [ 668 | "src/" 669 | ] 670 | }, 671 | "notification-url": "https://packagist.org/downloads/", 672 | "license": [ 673 | "BSD-3-Clause" 674 | ], 675 | "authors": [ 676 | { 677 | "name": "Jeff Welch", 678 | "email": "whatthejeff@gmail.com" 679 | }, 680 | { 681 | "name": "Volker Dusch", 682 | "email": "github@wallbash.com" 683 | }, 684 | { 685 | "name": "Bernhard Schussek", 686 | "email": "bschussek@2bepublished.at" 687 | }, 688 | { 689 | "name": "Sebastian Bergmann", 690 | "email": "sebastian@phpunit.de" 691 | } 692 | ], 693 | "description": "Provides the functionality to compare PHP values for equality", 694 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 695 | "keywords": [ 696 | "comparator", 697 | "compare", 698 | "equality" 699 | ], 700 | "time": "2015-07-26 15:48:44" 701 | }, 702 | { 703 | "name": "sebastian/diff", 704 | "version": "1.4.1", 705 | "source": { 706 | "type": "git", 707 | "url": "https://github.com/sebastianbergmann/diff.git", 708 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" 709 | }, 710 | "dist": { 711 | "type": "zip", 712 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", 713 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", 714 | "shasum": "" 715 | }, 716 | "require": { 717 | "php": ">=5.3.3" 718 | }, 719 | "require-dev": { 720 | "phpunit/phpunit": "~4.8" 721 | }, 722 | "type": "library", 723 | "extra": { 724 | "branch-alias": { 725 | "dev-master": "1.4-dev" 726 | } 727 | }, 728 | "autoload": { 729 | "classmap": [ 730 | "src/" 731 | ] 732 | }, 733 | "notification-url": "https://packagist.org/downloads/", 734 | "license": [ 735 | "BSD-3-Clause" 736 | ], 737 | "authors": [ 738 | { 739 | "name": "Kore Nordmann", 740 | "email": "mail@kore-nordmann.de" 741 | }, 742 | { 743 | "name": "Sebastian Bergmann", 744 | "email": "sebastian@phpunit.de" 745 | } 746 | ], 747 | "description": "Diff implementation", 748 | "homepage": "https://github.com/sebastianbergmann/diff", 749 | "keywords": [ 750 | "diff" 751 | ], 752 | "time": "2015-12-08 07:14:41" 753 | }, 754 | { 755 | "name": "sebastian/environment", 756 | "version": "1.3.7", 757 | "source": { 758 | "type": "git", 759 | "url": "https://github.com/sebastianbergmann/environment.git", 760 | "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716" 761 | }, 762 | "dist": { 763 | "type": "zip", 764 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716", 765 | "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716", 766 | "shasum": "" 767 | }, 768 | "require": { 769 | "php": ">=5.3.3" 770 | }, 771 | "require-dev": { 772 | "phpunit/phpunit": "~4.4" 773 | }, 774 | "type": "library", 775 | "extra": { 776 | "branch-alias": { 777 | "dev-master": "1.3.x-dev" 778 | } 779 | }, 780 | "autoload": { 781 | "classmap": [ 782 | "src/" 783 | ] 784 | }, 785 | "notification-url": "https://packagist.org/downloads/", 786 | "license": [ 787 | "BSD-3-Clause" 788 | ], 789 | "authors": [ 790 | { 791 | "name": "Sebastian Bergmann", 792 | "email": "sebastian@phpunit.de" 793 | } 794 | ], 795 | "description": "Provides functionality to handle HHVM/PHP environments", 796 | "homepage": "http://www.github.com/sebastianbergmann/environment", 797 | "keywords": [ 798 | "Xdebug", 799 | "environment", 800 | "hhvm" 801 | ], 802 | "time": "2016-05-17 03:18:57" 803 | }, 804 | { 805 | "name": "sebastian/exporter", 806 | "version": "1.2.1", 807 | "source": { 808 | "type": "git", 809 | "url": "https://github.com/sebastianbergmann/exporter.git", 810 | "reference": "7ae5513327cb536431847bcc0c10edba2701064e" 811 | }, 812 | "dist": { 813 | "type": "zip", 814 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e", 815 | "reference": "7ae5513327cb536431847bcc0c10edba2701064e", 816 | "shasum": "" 817 | }, 818 | "require": { 819 | "php": ">=5.3.3", 820 | "sebastian/recursion-context": "~1.0" 821 | }, 822 | "require-dev": { 823 | "phpunit/phpunit": "~4.4" 824 | }, 825 | "type": "library", 826 | "extra": { 827 | "branch-alias": { 828 | "dev-master": "1.2.x-dev" 829 | } 830 | }, 831 | "autoload": { 832 | "classmap": [ 833 | "src/" 834 | ] 835 | }, 836 | "notification-url": "https://packagist.org/downloads/", 837 | "license": [ 838 | "BSD-3-Clause" 839 | ], 840 | "authors": [ 841 | { 842 | "name": "Jeff Welch", 843 | "email": "whatthejeff@gmail.com" 844 | }, 845 | { 846 | "name": "Volker Dusch", 847 | "email": "github@wallbash.com" 848 | }, 849 | { 850 | "name": "Bernhard Schussek", 851 | "email": "bschussek@2bepublished.at" 852 | }, 853 | { 854 | "name": "Sebastian Bergmann", 855 | "email": "sebastian@phpunit.de" 856 | }, 857 | { 858 | "name": "Adam Harvey", 859 | "email": "aharvey@php.net" 860 | } 861 | ], 862 | "description": "Provides the functionality to export PHP variables for visualization", 863 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 864 | "keywords": [ 865 | "export", 866 | "exporter" 867 | ], 868 | "time": "2015-06-21 07:55:53" 869 | }, 870 | { 871 | "name": "sebastian/global-state", 872 | "version": "1.1.1", 873 | "source": { 874 | "type": "git", 875 | "url": "https://github.com/sebastianbergmann/global-state.git", 876 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" 877 | }, 878 | "dist": { 879 | "type": "zip", 880 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", 881 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", 882 | "shasum": "" 883 | }, 884 | "require": { 885 | "php": ">=5.3.3" 886 | }, 887 | "require-dev": { 888 | "phpunit/phpunit": "~4.2" 889 | }, 890 | "suggest": { 891 | "ext-uopz": "*" 892 | }, 893 | "type": "library", 894 | "extra": { 895 | "branch-alias": { 896 | "dev-master": "1.0-dev" 897 | } 898 | }, 899 | "autoload": { 900 | "classmap": [ 901 | "src/" 902 | ] 903 | }, 904 | "notification-url": "https://packagist.org/downloads/", 905 | "license": [ 906 | "BSD-3-Clause" 907 | ], 908 | "authors": [ 909 | { 910 | "name": "Sebastian Bergmann", 911 | "email": "sebastian@phpunit.de" 912 | } 913 | ], 914 | "description": "Snapshotting of global state", 915 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 916 | "keywords": [ 917 | "global state" 918 | ], 919 | "time": "2015-10-12 03:26:01" 920 | }, 921 | { 922 | "name": "sebastian/object-enumerator", 923 | "version": "1.0.0", 924 | "source": { 925 | "type": "git", 926 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 927 | "reference": "d4ca2fb70344987502567bc50081c03e6192fb26" 928 | }, 929 | "dist": { 930 | "type": "zip", 931 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26", 932 | "reference": "d4ca2fb70344987502567bc50081c03e6192fb26", 933 | "shasum": "" 934 | }, 935 | "require": { 936 | "php": ">=5.6", 937 | "sebastian/recursion-context": "~1.0" 938 | }, 939 | "require-dev": { 940 | "phpunit/phpunit": "~5" 941 | }, 942 | "type": "library", 943 | "extra": { 944 | "branch-alias": { 945 | "dev-master": "1.0.x-dev" 946 | } 947 | }, 948 | "autoload": { 949 | "classmap": [ 950 | "src/" 951 | ] 952 | }, 953 | "notification-url": "https://packagist.org/downloads/", 954 | "license": [ 955 | "BSD-3-Clause" 956 | ], 957 | "authors": [ 958 | { 959 | "name": "Sebastian Bergmann", 960 | "email": "sebastian@phpunit.de" 961 | } 962 | ], 963 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 964 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 965 | "time": "2016-01-28 13:25:10" 966 | }, 967 | { 968 | "name": "sebastian/recursion-context", 969 | "version": "1.0.2", 970 | "source": { 971 | "type": "git", 972 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 973 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791" 974 | }, 975 | "dist": { 976 | "type": "zip", 977 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", 978 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791", 979 | "shasum": "" 980 | }, 981 | "require": { 982 | "php": ">=5.3.3" 983 | }, 984 | "require-dev": { 985 | "phpunit/phpunit": "~4.4" 986 | }, 987 | "type": "library", 988 | "extra": { 989 | "branch-alias": { 990 | "dev-master": "1.0.x-dev" 991 | } 992 | }, 993 | "autoload": { 994 | "classmap": [ 995 | "src/" 996 | ] 997 | }, 998 | "notification-url": "https://packagist.org/downloads/", 999 | "license": [ 1000 | "BSD-3-Clause" 1001 | ], 1002 | "authors": [ 1003 | { 1004 | "name": "Jeff Welch", 1005 | "email": "whatthejeff@gmail.com" 1006 | }, 1007 | { 1008 | "name": "Sebastian Bergmann", 1009 | "email": "sebastian@phpunit.de" 1010 | }, 1011 | { 1012 | "name": "Adam Harvey", 1013 | "email": "aharvey@php.net" 1014 | } 1015 | ], 1016 | "description": "Provides functionality to recursively process PHP variables", 1017 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1018 | "time": "2015-11-11 19:50:13" 1019 | }, 1020 | { 1021 | "name": "sebastian/resource-operations", 1022 | "version": "1.0.0", 1023 | "source": { 1024 | "type": "git", 1025 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1026 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" 1027 | }, 1028 | "dist": { 1029 | "type": "zip", 1030 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1031 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1032 | "shasum": "" 1033 | }, 1034 | "require": { 1035 | "php": ">=5.6.0" 1036 | }, 1037 | "type": "library", 1038 | "extra": { 1039 | "branch-alias": { 1040 | "dev-master": "1.0.x-dev" 1041 | } 1042 | }, 1043 | "autoload": { 1044 | "classmap": [ 1045 | "src/" 1046 | ] 1047 | }, 1048 | "notification-url": "https://packagist.org/downloads/", 1049 | "license": [ 1050 | "BSD-3-Clause" 1051 | ], 1052 | "authors": [ 1053 | { 1054 | "name": "Sebastian Bergmann", 1055 | "email": "sebastian@phpunit.de" 1056 | } 1057 | ], 1058 | "description": "Provides a list of PHP built-in functions that operate on resources", 1059 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1060 | "time": "2015-07-28 20:34:47" 1061 | }, 1062 | { 1063 | "name": "sebastian/version", 1064 | "version": "2.0.0", 1065 | "source": { 1066 | "type": "git", 1067 | "url": "https://github.com/sebastianbergmann/version.git", 1068 | "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5" 1069 | }, 1070 | "dist": { 1071 | "type": "zip", 1072 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", 1073 | "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", 1074 | "shasum": "" 1075 | }, 1076 | "require": { 1077 | "php": ">=5.6" 1078 | }, 1079 | "type": "library", 1080 | "extra": { 1081 | "branch-alias": { 1082 | "dev-master": "2.0.x-dev" 1083 | } 1084 | }, 1085 | "autoload": { 1086 | "classmap": [ 1087 | "src/" 1088 | ] 1089 | }, 1090 | "notification-url": "https://packagist.org/downloads/", 1091 | "license": [ 1092 | "BSD-3-Clause" 1093 | ], 1094 | "authors": [ 1095 | { 1096 | "name": "Sebastian Bergmann", 1097 | "email": "sebastian@phpunit.de", 1098 | "role": "lead" 1099 | } 1100 | ], 1101 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1102 | "homepage": "https://github.com/sebastianbergmann/version", 1103 | "time": "2016-02-04 12:56:52" 1104 | }, 1105 | { 1106 | "name": "symfony/yaml", 1107 | "version": "v3.0.6", 1108 | "source": { 1109 | "type": "git", 1110 | "url": "https://github.com/symfony/yaml.git", 1111 | "reference": "0047c8366744a16de7516622c5b7355336afae96" 1112 | }, 1113 | "dist": { 1114 | "type": "zip", 1115 | "url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96", 1116 | "reference": "0047c8366744a16de7516622c5b7355336afae96", 1117 | "shasum": "" 1118 | }, 1119 | "require": { 1120 | "php": ">=5.5.9" 1121 | }, 1122 | "type": "library", 1123 | "extra": { 1124 | "branch-alias": { 1125 | "dev-master": "3.0-dev" 1126 | } 1127 | }, 1128 | "autoload": { 1129 | "psr-4": { 1130 | "Symfony\\Component\\Yaml\\": "" 1131 | }, 1132 | "exclude-from-classmap": [ 1133 | "/Tests/" 1134 | ] 1135 | }, 1136 | "notification-url": "https://packagist.org/downloads/", 1137 | "license": [ 1138 | "MIT" 1139 | ], 1140 | "authors": [ 1141 | { 1142 | "name": "Fabien Potencier", 1143 | "email": "fabien@symfony.com" 1144 | }, 1145 | { 1146 | "name": "Symfony Community", 1147 | "homepage": "https://symfony.com/contributors" 1148 | } 1149 | ], 1150 | "description": "Symfony Yaml Component", 1151 | "homepage": "https://symfony.com", 1152 | "time": "2016-03-04 07:55:57" 1153 | } 1154 | ], 1155 | "aliases": [], 1156 | "minimum-stability": "stable", 1157 | "stability-flags": [], 1158 | "prefer-stable": false, 1159 | "prefer-lowest": false, 1160 | "platform": { 1161 | "php": ">=5.4.0" 1162 | }, 1163 | "platform-dev": [] 1164 | } 1165 | --------------------------------------------------------------------------------