├── .travis.yml ├── tests ├── bootstrap.php └── Tsukanov │ └── SteamLocomotive │ └── Tests │ ├── Core │ ├── Interfaces │ │ └── ISteamWebAPIUtilTest.php │ └── Tools │ │ ├── DotaToolsTest.php │ │ ├── StoreToolsTest.php │ │ └── UserToolsTest.php │ └── MainTest.php ├── .gitignore ├── src └── Tsukanov │ └── SteamLocomotive │ ├── Core │ ├── Tool.php │ ├── Interfaces │ │ ├── ICSGOServers_730.php │ │ ├── ISteamWebAPIUtil.php │ │ ├── ISteamGameServerAccount.php │ │ ├── ISteamApps.php │ │ ├── IEconDOTA2_816.php │ │ ├── IEconDOTA2_570.php │ │ ├── IEconDOTA2_205790.php │ │ ├── ISteamRemoteStorage.php │ │ ├── IPlayerService.php │ │ ├── ISteamUser.php │ │ ├── ISteamUserStats.php │ │ ├── IDOTA2Match_816.php │ │ ├── IDOTA2Match_570.php │ │ └── IDOTA2Match_205790.php │ ├── Tools │ │ ├── Dota.php │ │ ├── Store.php │ │ └── User.php │ └── WebInterface.php │ └── Locomotive.php ├── CONTRIBUTING.md ├── phpunit.xml.dist ├── composer.json ├── README.md └── LICENSE.txt /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | 8 | install: 9 | - composer self-update 10 | - composer install --dev 11 | 12 | script: vendor/bin/phpunit 13 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | get($url); 13 | return $response->getBody(true); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/ICSGOServers_730.php: -------------------------------------------------------------------------------- 1 | $steamID 16 | ); 17 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /tests/Tsukanov/SteamLocomotive/Tests/Core/Interfaces/ISteamWebAPIUtilTest.php: -------------------------------------------------------------------------------- 1 | lib = new Locomotive(null); 16 | } 17 | 18 | public function testApiList() 19 | { 20 | $this->lib->ISteamWebAPIUtil->GetSupportedAPIList(); 21 | } 22 | 23 | public function testServerInfo() 24 | { 25 | $this->lib->ISteamWebAPIUtil->GetServerInfo(); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | ./tests/Tsukanov/SteamLocomotive/Tests/ 14 | 15 | 16 | 17 | 18 | 19 | ./src/Tsukanov/SteamLocomotive 20 | 21 | ./tests 22 | ./vendor 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/Tsukanov/SteamLocomotive/Tests/MainTest.php: -------------------------------------------------------------------------------- 1 | api_key = 'poop'; 17 | $this->lib = new Locomotive($this->api_key); 18 | } 19 | 20 | public function testAPIKey() 21 | { 22 | $this->assertEquals($this->api_key, $GLOBALS['LOCOMOTIVE_API_KEY']); 23 | } 24 | 25 | /** 26 | * Check if all interfaces are defined 27 | */ 28 | public function testInterfaces() 29 | { 30 | foreach (glob(LOCOMOTIVE_INTERFACES_PATH . '*.php') as $filewithpath) { 31 | $file = str_replace(LOCOMOTIVE_INTERFACES_PATH, '', $filewithpath); 32 | $filename = substr($file, 0, -4); 33 | $this->assertTrue(isset($this->lib->$filename)); 34 | } 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/ISteamApps.php: -------------------------------------------------------------------------------- 1 | $addr 21 | ); 22 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 23 | } 24 | 25 | /** 26 | * @param $appid uint32 AppID of game 27 | * @param $version uint32 The installed version of the game 28 | */ 29 | public function UpToDateCheck($appid, $version) 30 | { 31 | $params = array( 32 | 'appid' => $appid, 33 | 'version' => $version 34 | ); 35 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsukanov/steam-locomotive", 3 | "type": "library", 4 | "description": "PHP wrapper for Steam Web API with some useful tools", 5 | "license": "Apache-2.0", 6 | "homepage": "https://github.com/Tsukanov/steam-locomotive/", 7 | "keywords": ["steam", "valve", "dota", "tf2"], 8 | "authors": [ 9 | { 10 | "name": "Roman Tsukanov", 11 | "email": "roman@tsukanov.me", 12 | "homepage": "http://tsukanov.me/" 13 | }, 14 | { 15 | "name": "Steam Locomotive Community", 16 | "homepage": "https://github.com/tsukanov/steam-locomotive/graphs/contributors" 17 | } 18 | ], 19 | "require": { 20 | "ext-json": "*", 21 | "php": ">=5.4", 22 | "guzzlehttp/guzzle": "~4.0" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "~4.0" 26 | }, 27 | "autoload": { 28 | "psr-0": { 29 | "Tsukanov\\SteamLocomotive": "src/", 30 | "Tsukanov\\SteamLocomotive\\Tests": "tests/" 31 | 32 | } 33 | }, 34 | "minimum-stability": "dev" 35 | } 36 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Tools/Dota.php: -------------------------------------------------------------------------------- 1 | $language, 22 | 'itemizedonly' => $itemizedonly 23 | ); 24 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 25 | } 26 | 27 | /** 28 | * @param $language string The language to provide rarity names in. 29 | * @return mixed 30 | */ 31 | public function GetRarities($language = NULL) 32 | { 33 | $params = array( 34 | 'language' => $language 35 | ); 36 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 37 | } 38 | 39 | public function GetTournamentPrizePool($language = NULL) 40 | { 41 | $params = array( 42 | 'language' => $language 43 | ); 44 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/IEconDOTA2_570.php: -------------------------------------------------------------------------------- 1 | $language, 22 | 'itemizedonly' => $itemizedonly 23 | ); 24 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 25 | } 26 | 27 | /** 28 | * @param $language string The language to provide rarity names in. 29 | */ 30 | public function GetRarities($language = NULL) 31 | { 32 | $params = array( 33 | 'language' => $language 34 | ); 35 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 36 | } 37 | 38 | public function GetTournamentPrizePool($leagueid = NULL, $language = NULL) 39 | { 40 | $params = array( 41 | 'leagueid' => $leagueid, 42 | 'language' => $language 43 | ); 44 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /tests/Tsukanov/SteamLocomotive/Tests/Core/Tools/DotaToolsTest.php: -------------------------------------------------------------------------------- 1 | dota_tools = new Dota(); 16 | } 17 | 18 | public function testGetHeroIconURL() 19 | { 20 | $hero_name = 'techies'; 21 | $this->assertEquals('http://media.steampowered.com/apps/dota2/images/heroes/' . $hero_name . '_sb.png', $this->dota_tools->getHeroIconURL($hero_name)); 22 | } 23 | 24 | public function testGetItemIconURL() 25 | { 26 | $item_name = 'dagon'; 27 | $this->assertEquals('http://media.steampowered.com/apps/dota2/images/items/' . $item_name . '_lg.png', $this->dota_tools->getItemIconURL($item_name)); 28 | } 29 | 30 | function testGetHeroPickerData() 31 | { 32 | $this->dota_tools->getHeroPickerData(); 33 | } 34 | 35 | function testGetItemData() 36 | { 37 | $this->dota_tools->getItemData(); 38 | } 39 | 40 | function testGetAbilityData() 41 | { 42 | $this->dota_tools->getAbilityData(); 43 | } 44 | 45 | function testGetUniqueUsers() 46 | { 47 | $this->dota_tools->getUniqueUsers(); 48 | } 49 | 50 | function testGetIntlPrizePool() 51 | { 52 | $this->dota_tools->getIntlPrizePool(); 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/IEconDOTA2_205790.php: -------------------------------------------------------------------------------- 1 | $language, 22 | 'itemizedonly' => $itemizedonly 23 | ); 24 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 25 | } 26 | 27 | /** 28 | * @param $language string The language to provide rarity names in. 29 | * @return mixed 30 | */ 31 | public function GetRarities($language = NULL) 32 | { 33 | $params = array( 34 | 'language' => $language 35 | ); 36 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 37 | } 38 | 39 | public function GetTournamentPrizePool($leagueid = NULL, $language = NULL) 40 | { 41 | $params = array( 42 | 'leagueid' => $leagueid, 43 | 'language' => $language 44 | ); 45 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/WebInterface.php: -------------------------------------------------------------------------------- 1 | get(PROTOCOL . '://' . WEB_API_HOSTNAME . $url . self::parseParameters($parameters)); 21 | 22 | if ($response->getStatusCode() == 200) { 23 | return json_decode($response->getBody(true)); 24 | } 25 | } 26 | 27 | private function parseParameters($parameters = array()) 28 | { 29 | $param_keys = array_keys($parameters); 30 | $result = ''; 31 | foreach ($param_keys as $key) { 32 | $val = $parameters[$key]; 33 | if (!is_null($val)) { 34 | $result = $result . '&' . $key . '=' . $val; 35 | } 36 | } 37 | return $result; 38 | } 39 | 40 | function getClassName($object) 41 | { 42 | $class = get_class($object); 43 | $namespace_end = strrpos($class, '\\'); 44 | if ($namespace_end) { 45 | // Removing namespace 46 | return $name = substr($class, $namespace_end + 1); 47 | } else { 48 | return $class; 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/ISteamRemoteStorage.php: -------------------------------------------------------------------------------- 1 | $steamid, 18 | 'ugcid' => $ugcid, 19 | 'appid' => $appid 20 | ); 21 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 22 | } 23 | 24 | /** 25 | * @param $collectioncount uint32 Number of collection being requested 26 | * @param $publishedfileids uint64 collection ids to get the details for 27 | */ 28 | public function GetCollectionDetails($collectioncount, $publishedfileids) 29 | { 30 | $params = array( 31 | 'collectioncount' => $collectioncount, 32 | 'publishedfileids' => $publishedfileids 33 | ); 34 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 35 | } 36 | 37 | /** 38 | * @param $itemcount uint32 Number of items being requested 39 | * @param $publishedfileids uint64 published file id to look up 40 | */ 41 | public function GetPublishedFileDetails($itemcount, $publishedfileids) 42 | { 43 | $params = array( 44 | 'itemcount' => $itemcount, 45 | 'publishedfileids' => $publishedfileids 46 | ); 47 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Locomotive.php: -------------------------------------------------------------------------------- 1 | ICSGOServers_730 = new Interfaces\ICSGOServers_730(); 39 | $this->IDOTA2Match_570 = new Interfaces\IDOTA2Match_570(); 40 | $this->IDOTA2Match_816 = new Interfaces\IDOTA2Match_816(); 41 | $this->IDOTA2Match_205790 = new Interfaces\IDOTA2Match_205790(); 42 | $this->IEconDOTA2_570 = new Interfaces\IEconDOTA2_570(); 43 | $this->IEconDOTA2_816 = new Interfaces\IEconDOTA2_816(); 44 | $this->IEconDOTA2_205790 = new Interfaces\IEconDOTA2_205790(); 45 | $this->IPlayerService = new Interfaces\IPlayerService(); 46 | $this->ISteamApps = new Interfaces\ISteamApps(); 47 | $this->ISteamGameServerAccount = new Interfaces\ISteamGameServerAccount(); 48 | $this->ISteamRemoteStorage = new Interfaces\ISteamRemoteStorage(); 49 | $this->ISteamUser = new Interfaces\ISteamUser(); 50 | $this->ISteamUserStats = new Interfaces\ISteamUserStats(); 51 | $this->ISteamWebAPIUtil = new Interfaces\ISteamWebAPIUtil(); 52 | 53 | $this->tools = new LocomotiveTools(); 54 | } 55 | 56 | } 57 | 58 | class LocomotiveTools 59 | { 60 | 61 | public function __construct() 62 | { 63 | // Defining tools 64 | $this->store = new Tools\Store(); 65 | $this->dota = new Tools\Dota(); 66 | $this->user = new Tools\User(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/IPlayerService.php: -------------------------------------------------------------------------------- 1 | $steamid, 17 | 'count' => $count 18 | ); 19 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 20 | } 21 | 22 | /** 23 | * @param uint64 $steamid The player we're asking about 24 | * @param bool $include_appinfo true if we want additional details (name, icon) about each game 25 | * @param bool $include_played_free_games Free games are excluded by default. If this is set, free games the user has played will be returned. 26 | * @param uint32 $appids_filter if set, restricts result set to the passed in apps 27 | */ 28 | public function GetOwnedGames($steamid = NULL, 29 | $include_appinfo = NULL, 30 | $include_played_free_games = NULL, 31 | $appids_filter = NULL) 32 | { 33 | $params = array( 34 | 'steamid' => $steamid, 35 | 'include_appinfo' => $include_appinfo, 36 | 'include_played_free_games' => $include_played_free_games, 37 | 'appids_filter' => $appids_filter 38 | ); 39 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 40 | } 41 | 42 | public function GetSteamLevel($steamid) 43 | { 44 | $params = array( 45 | 'steamid' => $steamid 46 | ); 47 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 48 | } 49 | 50 | public function GetBadges($steamid) 51 | { 52 | $params = array( 53 | 'steamid' => $steamid 54 | ); 55 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 56 | } 57 | 58 | public function GetCommunityBadgeProgress($steamid, $badgeid) 59 | { 60 | $params = array( 61 | 'steamid' => $steamid, 62 | 'badgeid' => $badgeid 63 | ); 64 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 65 | } 66 | 67 | public function IsPlayingSharedGame($steamid, $appid_playing) 68 | { 69 | $params = array( 70 | 'steamid' => $steamid, 71 | 'appid_playing' => $appid_playing 72 | ); 73 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Steam Locomotive 2 | [![Build Status](https://img.shields.io/travis/gentlecat/steam-locomotive.svg)](https://travis-ci.org/gentlecat/steam-locomotive) 3 | [![Latest Stable Version](https://img.shields.io/packagist/v/tsukanov/steam-locomotive.svg)](https://packagist.org/packages/tsukanov/steam-locomotive) 4 | 5 | Steam Locomotive is a PHP wrapper for Steam Web API with useful tools such as Steam ID converters, validators, etc. 6 | 7 | **⚠️Please note that this project is no longer actively maintained by the original author!** 8 | The best way to make a change is by submitting a pull request. You can add missing interface, 9 | fix function that is not working properly or do something else. Any improvements are welcome! 10 | 11 | ## How it works 12 | 13 | This library wraps interfaces provided by Steam Web API into PHP classes and functions. 14 | It simplifies communication with Steam while preserving original structure of its API. 15 | Each interface, method, and parameter has the same name so you can easily start using this 16 | library if you worked with Steam Web API before. 17 | 18 | Also, this library provides some useful tools that are not available in official API, 19 | but might be needed. You can get additional details about applications, store, prices; 20 | convert Steam ID or validate one. 21 | 22 | ### Returned data format 23 | In most cases functions return JSON that is decoded using [`json_decode`](http://php.net/json_decode) function. 24 | *See PHPDoc comments to find out more about data returned by each function.* 25 | 26 | ## Usage example 27 | 28 | use Tsukanov\SteamLocomotive\Locomotive; 29 | $steam = new Locomotive(YOUR_STEAM_API_KEY); 30 | 31 | // Getting information about heroes in Dota 2 32 | $response = $steam->IEconDOTA2_570->GetHeroes(); 33 | 34 | ## Installation 35 | 36 | ### [Composer](http://getcomposer.org/) 37 | Composer is a tool for dependency management in PHP. Steam Locomotive is available as a 38 | [package](https://packagist.org/packages/tsukanov/steam-locomotive) for Composer. 39 | All you need to do is define the following requirement in your composer.json file: 40 | 41 | { 42 | "require": { 43 | "tsukanov/steam-locomotive": "0.3.0" 44 | } 45 | } 46 | 47 | ## License 48 | 49 | Copyright 2016 Roman Tsukanov 50 | 51 | Licensed under the Apache License, Version 2.0 (the "License"); 52 | you may not use this file except in compliance with the License. 53 | You may obtain a copy of the License at 54 | 55 | http://www.apache.org/licenses/LICENSE-2.0 56 | 57 | Unless required by applicable law or agreed to in writing, software 58 | distributed under the License is distributed on an "AS IS" BASIS, 59 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 60 | See the License for the specific language governing permissions and 61 | limitations under the License. 62 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/ISteamUser.php: -------------------------------------------------------------------------------- 1 | $steamID, 17 | 'relationship' => $relationship 18 | ); 19 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 20 | } 21 | 22 | /** 23 | * @param $steamids Array of steamIDs 24 | */ 25 | public function GetPlayerBans($steamids = array()) 26 | { 27 | $bans = null; 28 | foreach (array_chunk($steamids, 100) as $iteration => $chunk) { 29 | $params = array( 30 | 'steamids' => implode(",", $chunk) 31 | ); 32 | $response = self::get(self::getClassName($this), __FUNCTION__, 1, $params); 33 | if ($iteration === 0) { 34 | $bans = $response; 35 | } else { 36 | $bans->players = array_merge( 37 | $bans->players, 38 | $response->players 39 | ); 40 | } 41 | } 42 | return $bans; 43 | } 44 | 45 | /** 46 | * @param $steamid unit64 SteamID of user 47 | */ 48 | public function GetUserGroupList($steamid) 49 | { 50 | $params = array( 51 | 'steamid' => $steamid 52 | ); 53 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 54 | } 55 | 56 | /** 57 | * @param $vanityurl The vanity URL to get a SteamID for 58 | * @param null $url_type The type of vanity URL. 1 (default): Individual profile, 2: Group, 3: Official game group 59 | */ 60 | public function ResolveVanityURL($vanityurl, $url_type = NULL) 61 | { 62 | $params = array( 63 | 'vanityurl' => $vanityurl, 64 | 'url_type' => $url_type 65 | ); 66 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 67 | } 68 | 69 | /** 70 | * @param $steamids Array of steamIDs 71 | */ 72 | public function GetPlayerSummaries($steamids = array()) 73 | { 74 | $summaries = null; 75 | foreach (array_chunk($steamids, 100) as $iteration => $chunk) { 76 | $params = array( 77 | 'steamids' => implode(",", $chunk) 78 | ); 79 | $response = self::get(self::getClassName($this), __FUNCTION__, 2, $params); 80 | if ($iteration === 0) { 81 | $summaries = $response; 82 | } else { 83 | $summaries->response->players = array_merge( 84 | $summaries->response->players, 85 | $response->response->players 86 | ); 87 | } 88 | } 89 | return $summaries; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/ISteamUserStats.php: -------------------------------------------------------------------------------- 1 | $gameid 15 | ); 16 | return self::get(self::getClassName($this), __FUNCTION__, 2, $params); 17 | } 18 | 19 | /** 20 | * @param unit32 $appid AppID that we're getting user count for 21 | */ 22 | public function GetNumberOfCurrentPlayers($appid) 23 | { 24 | $params = array( 25 | 'appid' => $appid 26 | ); 27 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 28 | } 29 | 30 | /** 31 | * @param unit32 $appid AppID that we're getting global stats for 32 | * @param unit32 $count Number of stats get data for 33 | * @param string $name Names of stat to get data for 34 | * @param unit32 $startdate Start date for daily totals (unix epoch timestamp) 35 | * @param unit32 $enddate End date for daily totals (unix epoch timestamp) 36 | */ 37 | public function GetGlobalStatsForGame($appid, $count, $name, $startdate = NULL, $enddate = NULL) 38 | { 39 | $params = array( 40 | 'appid' => $appid, 41 | 'count' => $count, 42 | 'name' => $name, 43 | 'startdate' => $startdate, 44 | 'enddate' => $enddate 45 | ); 46 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 47 | } 48 | 49 | /** 50 | * @param unit32 $appid appid of game 51 | * @param string $l localized language to return (english, french, etc.) 52 | */ 53 | public function GetSchemaForGame($appid, $l = NULL) 54 | { 55 | $params = array( 56 | 'appid' => $appid, 57 | 'l' => $l 58 | ); 59 | return self::get(self::getClassName($this), __FUNCTION__, 2, $params); 60 | } 61 | 62 | /** 63 | * @param unit32 $appid appid of game 64 | * @param unit64 $steamid SteamID of user 65 | */ 66 | public function GetUserStatsForGame($appid, $steamid) 67 | { 68 | $params = array( 69 | 'appid' => $appid, 70 | 'steamid' => $steamid 71 | ); 72 | return self::get(self::getClassName($this), __FUNCTION__, 2, $params); 73 | } 74 | 75 | /** 76 | * @param unit32 $steamid SteamID of user 77 | * @param unit32 $appid AppID to get achievements for 78 | * @param string $language Language to return strings for 79 | */ 80 | public function GetPlayerAchievements($steamid, $appid, $l = NULL) 81 | { 82 | $params = array( 83 | 'steamid' => $steamid, 84 | 'appid' => $appid, 85 | 'l' => $l 86 | ); 87 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 88 | } 89 | 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/IDOTA2Match_816.php: -------------------------------------------------------------------------------- 1 | $match_id 13 | ); 14 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 15 | } 16 | 17 | public function GetTeamInfoByTeamID($start_at_team_id = NULL, $teams_requested = NULL) 18 | { 19 | $params = array( 20 | 'start_at_team_id' => $start_at_team_id, 21 | 'teams_requested' => $teams_requested 22 | ); 23 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 24 | } 25 | 26 | public function GetLiveLeagueGames() 27 | { 28 | return self::get(self::getClassName($this), __FUNCTION__, 1); 29 | } 30 | 31 | public function GetLeagueListing() 32 | { 33 | return self::get(self::getClassName($this), __FUNCTION__, 1); 34 | } 35 | 36 | public function GetScheduledLeagueGames($date_min = NULL, $date_max = NULL) 37 | { 38 | $params = array( 39 | 'date_min' => $date_min, 40 | 'date_max' => $date_max 41 | ); 42 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 43 | } 44 | 45 | public function GetMatchHistoryBySequenceNum($start_at_match_seq_num = NULL, $matches_requested = NULL) 46 | { 47 | $params = array( 48 | 'start_at_match_seq_num' => $start_at_match_seq_num, 49 | 'matches_requested' => $matches_requested 50 | ); 51 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 52 | } 53 | 54 | public function GetMatchHistory($matches_requested = NULL, 55 | $start_at_match_id = NULL, 56 | $account_id = NULL, 57 | $date_max = NULL, 58 | $date_min = NULL, 59 | $skill = NULL, 60 | $hero_id = NULL, 61 | $league_id = NULL, 62 | $tournament_games_only = NULL, 63 | $min_players = NULL, 64 | $game_mode = NULL) 65 | { 66 | $params = array( 67 | 'match_id' => $matches_requested, 68 | 'start_at_match_id' => $start_at_match_id, 69 | 'account_id' => $account_id, 70 | 'date_min' => $date_min, 71 | 'date_max' => $date_max, 72 | 'skill' => $skill, 73 | 'hero_id' => $hero_id, 74 | 'league_id' => $league_id, 75 | 'tournament_games_only' => $tournament_games_only, 76 | 'min_players' => $min_players, 77 | 'game_mode' => $game_mode, 78 | ); 79 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /tests/Tsukanov/SteamLocomotive/Tests/Core/Tools/StoreToolsTest.php: -------------------------------------------------------------------------------- 1 | store_tools = new Store(); 22 | } 23 | public function testGetAppLogoURL() 24 | { 25 | $app_id = $this->appids[0]; 26 | $this->assertEquals('http://cdn.akamai.steamstatic.com/steam/apps/' . $app_id . '/header.jpg', $this->store_tools->getAppLogoURL($app_id)); 27 | 28 | $app_id = $this->appids[1]; 29 | $this->assertEquals('http://cdn.akamai.steamstatic.com/steam/apps/' . $app_id . '/header.jpg', $this->store_tools->getAppLogoURL($app_id)); 30 | } 31 | 32 | /** 33 | * @test 34 | * @group failing 35 | */ 36 | function appdetails_will_be_null_if_response_was_not_succesful() 37 | { 38 | /** @var \PHPUnit_Framework_MockObject_MockObject|\Tsukanov\SteamLocomotive\Core\Tools\Store $mockedStoreTools */ 39 | $mockedStoreTools = $this->getMockBuilder('\Tsukanov\SteamLocomotive\Core\Tools\Store') 40 | ->setMethods(['getContent']) 41 | ->getMock(); 42 | 43 | $mockedStoreTools->expects($this->exactly(2)) 44 | ->method('getContent') 45 | ->willReturn('{"123": {"success": false}}'); 46 | 47 | $this->assertEquals(null, $mockedStoreTools->getAppDetails(123)); 48 | $this->assertEquals(null, $mockedStoreTools->getAppUserDetails(123)); 49 | } 50 | 51 | /** 52 | * @group failing 53 | */ 54 | function testGetAppDetails() 55 | { 56 | /** @var \PHPUnit_Framework_MockObject_MockObject|\Tsukanov\SteamLocomotive\Core\Tools\Store $mockedStoreTools */ 57 | $mockedStoreTools = $this->getMockBuilder('\Tsukanov\SteamLocomotive\Core\Tools\Store') 58 | ->setMethods(['getContent']) 59 | ->getMock(); 60 | 61 | $mockedStoreTools->expects($this->once()) 62 | ->method('getContent') 63 | ->willThrowException(ClientException::create( 64 | new Request('GET', 'something'), 65 | new Response(400, [], Stream::factory('null')) 66 | )); 67 | 68 | $this->assertEquals(null, $mockedStoreTools->getAppDetails(123)); 69 | } 70 | 71 | function testGetAppUserDetails() 72 | { 73 | $result = $this->store_tools->getAppUserDetails(10); 74 | $this->assertEquals('Counter-Strike', $result->name); 75 | } 76 | 77 | function testGetPackageDetails() 78 | { 79 | $this->store_tools->getPackageDetails($this->packageids); 80 | } 81 | 82 | function testGetFeatured() 83 | { 84 | $this->store_tools->getFeatured(); 85 | } 86 | 87 | function testGetFeaturedCategories() 88 | { 89 | $this->store_tools->getFeaturedCategories(); 90 | } 91 | 92 | function testGetSalePage() 93 | { 94 | $this->store_tools->getSalePage(0); 95 | } 96 | } -------------------------------------------------------------------------------- /tests/Tsukanov/SteamLocomotive/Tests/Core/Tools/UserToolsTest.php: -------------------------------------------------------------------------------- 1 | user_tools = new User(); 16 | } 17 | 18 | public function testIdTypeDetector() 19 | { 20 | $this->assertEquals(USER_ID_TYPE_VANITY, $this->user_tools->getTypeOfId("Rabscuttle")); 21 | $this->assertEquals(USER_ID_TYPE_VANITY, $this->user_tools->getTypeOfId("robinwalker")); 22 | 23 | $this->assertEquals(USER_ID_TYPE_COMMUNITY, $this->user_tools->getTypeOfId(76561197960287930)); 24 | $this->assertEquals(USER_ID_TYPE_COMMUNITY, $this->user_tools->getTypeOfId(76561197960435530)); 25 | $this->assertEquals(USER_ID_TYPE_COMMUNITY, $this->user_tools->getTypeOfId(76561197960265741)); 26 | 27 | $this->assertEquals(USER_ID_TYPE_STEAM, $this->user_tools->getTypeOfId("STEAM_0:0:11101")); 28 | $this->assertEquals(USER_ID_TYPE_STEAM, $this->user_tools->getTypeOfId("STEAM_0:0:84901")); 29 | $this->assertEquals(USER_ID_TYPE_STEAM, $this->user_tools->getTypeOfId("STEAM_0:1:6")); 30 | 31 | $this->assertEquals(USER_ID_TYPE_STEAM, $this->user_tools->getTypeOfId("0:0:11101")); 32 | $this->assertEquals(USER_ID_TYPE_STEAM, $this->user_tools->getTypeOfId("0:0:84901")); 33 | $this->assertEquals(USER_ID_TYPE_STEAM, $this->user_tools->getTypeOfId("0:1:6")); 34 | } 35 | 36 | public function testIdValidator() 37 | { 38 | $this->assertTrue($this->user_tools->validateUserId("Rabscuttle", USER_ID_TYPE_VANITY)); 39 | $this->assertTrue($this->user_tools->validateUserId("robinwalker", USER_ID_TYPE_VANITY)); 40 | 41 | $this->assertTrue($this->user_tools->validateUserId(76561197960287930, USER_ID_TYPE_COMMUNITY)); 42 | $this->assertTrue($this->user_tools->validateUserId(76561197960435530, USER_ID_TYPE_COMMUNITY)); 43 | $this->assertTrue($this->user_tools->validateUserId(76561197960265741, USER_ID_TYPE_COMMUNITY)); 44 | 45 | $this->assertTrue($this->user_tools->validateUserId("STEAM_0:0:11101", USER_ID_TYPE_STEAM)); 46 | $this->assertTrue($this->user_tools->validateUserId("STEAM_0:0:84901", USER_ID_TYPE_STEAM)); 47 | $this->assertTrue($this->user_tools->validateUserId("STEAM_0:1:6", USER_ID_TYPE_STEAM)); 48 | 49 | $this->assertTrue($this->user_tools->validateUserId("0:0:11101", USER_ID_TYPE_STEAM)); 50 | $this->assertTrue($this->user_tools->validateUserId("0:1:6", USER_ID_TYPE_STEAM)); 51 | } 52 | 53 | public function testCommunityIdConverter() 54 | { 55 | $this->assertEquals(76561197960287930, $this->user_tools->convertToCommunityId(76561197960287930)); 56 | $this->assertEquals(76561197960435530, $this->user_tools->convertToCommunityId(76561197960435530)); 57 | 58 | $this->assertEquals(76561197960287930, $this->user_tools->convertToCommunityId("STEAM_0:0:11101")); 59 | $this->assertEquals(76561197960435530, $this->user_tools->convertToCommunityId("STEAM_0:0:84901")); 60 | $this->assertEquals(76561197960265741, $this->user_tools->convertToCommunityId("0:1:6")); 61 | 62 | $this->assertEquals(76561197960287930, $this->user_tools->convertToCommunityId("0:0:11101")); 63 | $this->assertEquals(76561197960435530, $this->user_tools->convertToCommunityId("0:0:84901")); 64 | $this->assertEquals(76561197960265741, $this->user_tools->convertToCommunityId("0:1:6")); 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/IDOTA2Match_570.php: -------------------------------------------------------------------------------- 1 | $match_id 13 | ); 14 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 15 | } 16 | 17 | public function GetTeamInfoByTeamID($start_at_team_id = NULL, $teams_requested = NULL) 18 | { 19 | $params = array( 20 | 'start_at_team_id' => $start_at_team_id, 21 | 'teams_requested' => $teams_requested 22 | ); 23 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 24 | } 25 | 26 | public function GetLiveLeagueGames() 27 | { 28 | return self::get(self::getClassName($this), __FUNCTION__, 1); 29 | } 30 | 31 | public function GetLeagueListing() 32 | { 33 | return self::get(self::getClassName($this), __FUNCTION__, 1); 34 | } 35 | 36 | public function GetScheduledLeagueGames($date_min = NULL, $date_max = NULL) 37 | { 38 | $params = array( 39 | 'date_min' => $date_min, 40 | 'date_max' => $date_max 41 | ); 42 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 43 | } 44 | 45 | public function GetMatchHistoryBySequenceNum($start_at_match_seq_num = NULL, $matches_requested = NULL) 46 | { 47 | $params = array( 48 | 'start_at_match_seq_num' => $start_at_match_seq_num, 49 | 'matches_requested' => $matches_requested 50 | ); 51 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 52 | } 53 | 54 | public function GetTournamentPlayerStats($account_id, 55 | $match_id = NULL, 56 | $hero_id = NULL, 57 | $league_id = NULL, 58 | $time_frame = NULL) 59 | { 60 | $params = array( 61 | 'account_id' => $account_id, 62 | 'match_id' => $match_id, 63 | 'hero_id' => $hero_id, 64 | 'league_id' => $league_id, 65 | 'time_frame' => $time_frame, 66 | ); 67 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 68 | } 69 | 70 | public function GetMatchHistory($matches_requested = NULL, 71 | $start_at_match_id = NULL, 72 | $account_id = NULL, 73 | $date_max = NULL, 74 | $date_min = NULL, 75 | $skill = NULL, 76 | $hero_id = NULL, 77 | $league_id = NULL, 78 | $tournament_games_only = NULL, 79 | $min_players = NULL, 80 | $game_mode = NULL) 81 | { 82 | $params = array( 83 | 'match_id' => $matches_requested, 84 | 'start_at_match_id' => $start_at_match_id, 85 | 'account_id' => $account_id, 86 | 'date_min' => $date_min, 87 | 'date_max' => $date_max, 88 | 'skill' => $skill, 89 | 'hero_id' => $hero_id, 90 | 'league_id' => $league_id, 91 | 'tournament_games_only' => $tournament_games_only, 92 | 'min_players' => $min_players, 93 | 'game_mode' => $game_mode, 94 | ); 95 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Interfaces/IDOTA2Match_205790.php: -------------------------------------------------------------------------------- 1 | $match_id 14 | ); 15 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 16 | } 17 | 18 | public function GetTeamInfoByTeamID($start_at_team_id = NULL, $teams_requested = NULL) 19 | { 20 | $params = array( 21 | 'start_at_team_id' => $start_at_team_id, 22 | 'teams_requested' => $teams_requested 23 | ); 24 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 25 | } 26 | 27 | public function GetLiveLeagueGames() 28 | { 29 | return self::get(self::getClassName($this), __FUNCTION__, 1); 30 | } 31 | 32 | public function GetLeagueListing() 33 | { 34 | return self::get(self::getClassName($this), __FUNCTION__, 1); 35 | } 36 | 37 | public function GetMatchHistoryBySequenceNum($start_at_match_seq_num = NULL, $matches_requested = NULL) 38 | { 39 | $params = array( 40 | 'start_at_match_seq_num' => $start_at_match_seq_num, 41 | 'matches_requested' => $matches_requested 42 | ); 43 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 44 | } 45 | 46 | public function GetScheduledLeagueGames($date_min = NULL, $date_max = NULL) 47 | { 48 | $params = array( 49 | 'date_min' => $date_min, 50 | 'date_max' => $date_max 51 | ); 52 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 53 | } 54 | 55 | public function GetTournamentPlayerStats($account_id, 56 | $match_id = NULL, 57 | $hero_id = NULL, 58 | $league_id = NULL, 59 | $time_frame = NULL) 60 | { 61 | $params = array( 62 | 'account_id' => $account_id, 63 | 'match_id' => $match_id, 64 | 'hero_id' => $hero_id, 65 | 'league_id' => $league_id, 66 | 'time_frame' => $time_frame, 67 | ); 68 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 69 | } 70 | 71 | public function GetMatchHistory($matches_requested = NULL, 72 | $start_at_match_id = NULL, 73 | $account_id = NULL, 74 | $date_max = NULL, 75 | $date_min = NULL, 76 | $skill = NULL, 77 | $hero_id = NULL, 78 | $league_id = NULL, 79 | $tournament_games_only = NULL, 80 | $min_players = NULL, 81 | $game_mode = NULL) 82 | { 83 | $params = array( 84 | 'match_id' => $matches_requested, 85 | 'start_at_match_id' => $start_at_match_id, 86 | 'account_id' => $account_id, 87 | 'date_min' => $date_min, 88 | 'date_max' => $date_max, 89 | 'skill' => $skill, 90 | 'hero_id' => $hero_id, 91 | 'league_id' => $league_id, 92 | 'tournament_games_only' => $tournament_games_only, 93 | 'min_players' => $min_players, 94 | 'game_mode' => $game_mode, 95 | ); 96 | return self::get(self::getClassName($this), __FUNCTION__, 1, $params); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Tools/Store.php: -------------------------------------------------------------------------------- 1 | getContent($url); 48 | $data = json_decode($json); 49 | $app = $data->{$appId}; 50 | if (!$app->success) { 51 | return null; 52 | } 53 | return $app->data; 54 | } catch (\GuzzleHttp\Exception\ClientException $e) { 55 | if (!$e->getResponse()) { 56 | throw $e; 57 | } 58 | 59 | if ((string) $e->getResponse()->getBody() === 'null') { 60 | return null; 61 | } 62 | 63 | throw $e; 64 | } 65 | } 66 | 67 | /** 68 | * @param int $appId 69 | * @return null|\stdClass 70 | */ 71 | function getAppUserDetails(/* int */ $appId) /*: array */ 72 | { 73 | $url = "http://store.steampowered.com/api/appdetails/?appids=$appId"; 74 | 75 | try { 76 | $json = $this->getContent($url); 77 | $data = json_decode($json); 78 | $app = $data->{$appId}; 79 | if (!$app->success) { 80 | return null; 81 | } 82 | return $app->data; 83 | } catch (\GuzzleHttp\Exception\ClientException $e) { 84 | if (!$e->getResponse()) { 85 | throw $e; 86 | } 87 | 88 | if ((string) $e->getResponse()->getBody() === 'null') { 89 | return null; 90 | } 91 | 92 | throw $e; 93 | } 94 | } 95 | 96 | function getPackageDetails($packageids = array()) 97 | { 98 | $url = 'http://store.steampowered.com/api/packagedetails/?packageids=' . implode(",", $packageids); 99 | return json_decode(parent::getContent($url)); 100 | } 101 | 102 | function getFeatured($cc = 'US', $language = 'english') 103 | { 104 | $url = 'http://store.steampowered.com/api/featured/?l=' . $language . '&cc=' . $cc; 105 | return json_decode(parent::getContent($url)); 106 | } 107 | 108 | function getFeaturedCategories($cc = 'US', $language = 'english') 109 | { 110 | $url = 'http://store.steampowered.com/api/featuredcategories/?l=' . $language . '&cc=' . $cc; 111 | return json_decode(parent::getContent($url)); 112 | } 113 | 114 | function getSalePage($id) 115 | { 116 | $url = 'http://store.steampowered.com/api/salepage/?id=' . $id; 117 | return json_decode(parent::getContent($url)); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/Tsukanov/SteamLocomotive/Core/Tools/User.php: -------------------------------------------------------------------------------- 1 | ResolveVanityURL($id); 27 | case USER_ID_TYPE_STEAM: 28 | return self::steamIdToCommunityId($id); 29 | default: 30 | return FALSE; 31 | } 32 | } 33 | 34 | /** 35 | * Returns type of supplied ID 36 | * @param mixed $id User ID 37 | * @return bool|string Returns type of ID or FALSE if not determined 38 | */ 39 | public function getTypeOfId($id) 40 | { 41 | if (self::validateUserId($id, USER_ID_TYPE_COMMUNITY)) return USER_ID_TYPE_COMMUNITY; 42 | if (self::validateUserId($id, USER_ID_TYPE_STEAM)) return USER_ID_TYPE_STEAM; 43 | if (self::validateUserId($id, USER_ID_TYPE_VANITY)) return USER_ID_TYPE_VANITY; 44 | return FALSE; 45 | } 46 | 47 | /** 48 | * @param mixed $id User ID 49 | * @param string $expected_type Expected type of ID 50 | * @return bool TRUE if correct, FALSE otherwise 51 | */ 52 | public function validateUserId($id, $expected_type) 53 | { 54 | switch ($expected_type) { 55 | case USER_ID_TYPE_COMMUNITY: 56 | if ((ctype_digit($id) && (strlen($id) == 17)) || (is_numeric($id) && $id > 76561197960265728 )) return TRUE; 57 | else return FALSE; 58 | case USER_ID_TYPE_STEAM: 59 | if (preg_match('/((?i:STEAM)_)?0:[0-9]:[0-9]*/', $id)) return TRUE; 60 | else return FALSE; 61 | case USER_ID_TYPE_VANITY: 62 | // TODO: Validate 63 | if (TRUE) return TRUE; 64 | else return FALSE; 65 | default: 66 | return FALSE; 67 | } 68 | } 69 | 70 | /** 71 | * Converts Steam ID to Community ID 72 | * Example input: STEAM_0:0:17336203 or 0:0:17336203 73 | * @param string $steam_id Full or short Steam ID 74 | * @return string Community ID 75 | * @throws WrongIDException 76 | */ 77 | public function steamIdToCommunityId($steam_id) 78 | { 79 | $x = NULL; 80 | $y = NULL; 81 | if (preg_match('/(?i:STEAM)_0:[0-9]:[0-9]*/', $steam_id)) { 82 | $x = substr($steam_id, 8, 1); 83 | $y = substr($steam_id, 10); 84 | } elseif (preg_match('/0:[0-9]:[0-9]*/', $steam_id)) { 85 | $x = substr($steam_id, 2, 1); 86 | $y = substr($steam_id, 4); 87 | } else { 88 | throw new WrongIDException($steam_id); 89 | } 90 | return ($y * 2) + $x + 76561197960265728; 91 | } 92 | 93 | /** 94 | * Converts Community ID to Steam ID 95 | * @param int $community_id Community ID 96 | * @param bool $is_short Is short Steam ID required 97 | * @return string Steam ID 98 | * @throws WrongIDException 99 | */ 100 | public function communityIdToSteamId($community_id, $is_short = FALSE) 101 | { 102 | $temp = intval($community_id) - 76561197960265728; 103 | $odd_id = $temp % 2; 104 | $temp = floor($temp / 2); 105 | if ($is_short) { 106 | return $odd_id . ':' . $temp; 107 | } else { 108 | return 'STEAM_0:' . $odd_id . ':' . $temp; 109 | } 110 | } 111 | 112 | } 113 | 114 | class WrongIDException extends \Exception 115 | { 116 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. --------------------------------------------------------------------------------