{"action":"created","comment":{"url":"https://api.github.com/repos/wesnoth/wesnoth/pulls/comments/38910299","id":38910299,"diff_hunk":"@@ -24,537 +25,471 @@\n \n #include <boost/foreach.hpp>\n #include <boost/algorithm/string/join.hpp>\n+#include <boost/algorithm/string.hpp>\n+#include <boost/algorithm/string/predicate.hpp>\n+#include <boost/bind.hpp>\n \n #include \"key.hpp\"\n \n+#include \"SDL.h\"\n+\n+#if !SDL_VERSION_ATLEAST(2,0,0)\n+#include \"sdl/keyboard.hpp\"\n+#endif\n+\n static lg::log_domain log_config(\"config\");\n #define ERR_G  LOG_STREAM(err,   lg::general)\n #define LOG_G  LOG_STREAM(info,  lg::general)\n #define DBG_G  LOG_STREAM(debug, lg::general)\n #define ERR_CF LOG_STREAM(err,   log_config)\n \n-namespace {\n+namespace hotkey {\n \n-std::vector<hotkey::hotkey_item> hotkeys_;\n+hotkey_list hotkeys_;\n config default_hotkey_cfg_;\n \n-hotkey::hotkey_item null_hotkey_(\"null\");\n-\n-hotkey::hotkey_item& get_hotkey(int mouse, int joystick, int button, int hat, int value,\n-\t\tbool shift, bool ctrl, bool cmd, bool alt)\n+static unsigned int sdl_get_mods()\n {\n-\tstd::vector<hotkey::hotkey_item>::iterator itor;\n+\tunsigned int mods;\n+\tmods = SDL_GetModState();\n \n-\tfor (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {\n+\tmods &= ~KMOD_NUM;\n+\tmods &= ~KMOD_CAPS;\n+\tmods &= ~KMOD_MODE;\n \n-\t\tif ( !( hotkey::is_scope_active(hotkey::get_hotkey_command(itor->get_command()).scope) && itor->active() ) ) {\n-\t\t\tcontinue;\n-\t\t}\n+\t// save the matching for checking right vs left keys\n+\tif (mods & KMOD_SHIFT)\n+\t\tmods |= KMOD_SHIFT;\n \n-\t\tif ( itor->get_shift() != shift || itor->get_ctrl() != ctrl\n-\t\t\t\t|| itor->get_cmd() != cmd || itor->get_alt() != alt ) {\n-\t\t\tcontinue;\n-\t\t}\n+\tif (mods & KMOD_CTRL)\n+\t\tmods |= KMOD_CTRL;\n \n-\t\tif ( itor->get_joystick() == joystick && itor->get_button() == button\n-\t\t\t\t&& itor->get_hat() == hat && itor->get_value() == value\n-\t\t\t\t&& itor->get_mouse() == mouse ) {\n-\t\t\treturn *itor;\n-\t\t}\n-\t}\n+\tif (mods & KMOD_ALT)\n+\t\tmods |= KMOD_ALT;\n \n-\treturn null_hotkey_;\n+#if SDL_VERSION_ATLEAST(2,0,0)\n+\tif (mods & KMOD_GUI)\n+\tmods |= KMOD_GUI;\n+#else\n+\tif (mods & KMOD_META)\n+\t\tmods |= KMOD_META;\n+#endif\n+\n+\treturn mods;\n }\n \n-hotkey::hotkey_item& get_hotkey(int character, int keycode,\n-\t\tbool shift, bool ctrl,\tbool cmd, bool alt)\n+const std::string hotkey_base::get_name() const\n {\n-\tstd::vector<hotkey::hotkey_item>::iterator itor;\n-\n-\tDBG_G << \"getting hotkey: char=\" << lexical_cast<std::string>(character)\n-\t\t<< \" keycode=\"  << lexical_cast<std::string>(keycode) << \" \"\n-\t\t<< (shift ? \"shift,\" : \"\")\n-\t\t<< (ctrl  ? \"ctrl,\"  : \"\")\n-\t\t<< (cmd   ? \"cmd,\"   : \"\")\n-\t\t<< (alt   ? \"alt,\"   : \"\")\n-\t\t<< \"\\n\";\n-\n-\t// Sometimes control modifies by -64, ie ^A == 1.\n-\tif (0 < character && character < 64 && ctrl) {\n-\t\tif (shift) {\n-\t\t\tcharacter += 64;\n-\t\t} else {\n-\t\t\tcharacter += 96;\n-\t\t}\n-\t\t/// @todo\n-\t\tDBG_G << \"Mapped to character \" << lexical_cast<std::string>(character) << \"\\n\";\n-\t}\n-\n-\t// For some reason on Mac OS, if cmd and shift are down, the character doesn't get upper-cased\n-\tif (cmd && character > 96 && character < 123 && shift) {\n-\t\tcharacter -= 32; }\n-\n-\tbool found = false;\n-\n-\tfor (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {\n-\t\t// Special case for Ctrl+Return/Enter keys, which gets resolved to Ctrl-j and Ctrl-m characters (LF and CR respectively).\n-\t\t// In such cases, do not match by character but go straight to key code.\n-\t\tif (itor->get_character() != -1 &&\n-\t\t\t!(tolower(character) == 'j' && keycode != SDLK_j) &&\n-\t\t\t!(tolower(character) == 'm' && keycode != SDLK_m)) {\n-\t\t\tif (character == itor->get_character()) {\n-\t\t\t\tif (ctrl == itor->get_ctrl()\n-\t\t\t\t\t\t&& cmd == itor->get_cmd()\n-\t\t\t\t\t\t&& alt == itor->get_alt()) {\n-\t\t\t\t\tif (hotkey::is_scope_active(hotkey::get_hotkey_command(itor->get_command()).scope) && itor->active()) {\n-\t\t\t\t\t\tDBG_G << \"Could match by character...\" << \"yes\\n\";\n-\t\t\t\t\t\tfound = true;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t} else {\n-\t\t\t\t\t\tDBG_G << \"Could match by character...\" << \"yes, but scope is inactive\\n\";\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\tDBG_G << \"Could match by character...\" << \"but modifiers different\\n\";\n-\t\t\t}\n-\t\t} else if (itor->get_keycode() != -1) {\n-\t\t\tif (keycode == itor->get_keycode()) {\n-\t\t\t\tif (shift == itor->get_shift()\n-\t\t\t\t\t\t&& ctrl == itor->get_ctrl()\n-\t\t\t\t\t\t&& cmd  == itor->get_cmd()\n-\t\t\t\t\t\t&& alt  == itor->get_alt()) {\n-\t\t\t\t\tif (hotkey::is_scope_active(hotkey::get_hotkey_command(itor->get_command()).scope) && itor->active()) {\n-\t\t\t\t\t\tDBG_G << \"Could match by keycode...\" << \"yes\\n\";\n-\t\t\t\t\t\tfound = true;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t} else {\n-\t\t\t\t\t\tDBG_G << \"Could match by keycode...\" << \"yes, but scope is inactive\\n\";\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\tDBG_G << \"Could match by keycode...\" << \"but modifiers different\\n\";\n-\t\t\t}\n-\t\t}\n-\t\tif (found) { break; }\n-\t}\n-\n-\tif (!found) {\n-\t\treturn null_hotkey_; }\n+\tstd::string ret = \"\";\n+\n+\tif (mod_ & KMOD_CTRL)\n+\t\tret += \"ctrl\";\n+\n+\tret +=\n+\t\t\t(!ret.empty() && !boost::algorithm::ends_with(ret, \"+\") ?\n+\t\t\t\t\t\"+\" : \"\");\n+\tif (mod_ & KMOD_ALT)\n+\t\tret += \"alt\";\n+\n+\tret +=\n+\t\t\t(!ret.empty() && !boost::algorithm::ends_with(ret, \"+\") ?\n+\t\t\t\t\t\"+\" : \"\");\n+\tif (mod_ & KMOD_SHIFT)\n+\t\tret += \"shift\";\n+\n+\tret +=\n+\t\t\t(!ret.empty() && !boost::algorithm::ends_with(ret, \"+\") ?\n+\t\t\t\t\t\"+\" : \"\");\n+#if SDL_VERSION_ATLEAST(2, 0, 0)\n+\tif (mod_ & KMOD_GUI)\n+#else\n+\tif (mod_ & KMOD_META)\n+#endif\n+#ifdef __APPLE__\n+\t\tret += \"cmd\";\n+#else\n+\t\tret += \"win\";\n+#endif\n \n-\treturn *itor;\n+\tret +=\n+\t\t\t(!ret.empty() && !boost::algorithm::ends_with(ret, \"+\") ?\n+\t\t\t\t\t\"+\" : \"\");\n+\treturn ret += get_name_helper();\n }\n \n+bool hotkey_base::bindings_equal(hotkey_ptr other)\n+{\n \n-}\n+\tbool ret;\n \n-namespace hotkey {\n+\tif (other == hotkey_ptr()) {\n+\t\treturn false;\n+\t}\n \n+\thk_scopes scopematch = hotkey::get_hotkey_command(get_command()).scope\n+\t\t\t& hotkey::get_hotkey_command(other->get_command()).scope;\n \n-const hotkey_item& get_hotkey(const SDL_JoyButtonEvent& event)\n-{\n-\tCKey keystate;\n-\tbool shift = keystate[SDLK_RSHIFT] || keystate[SDLK_LSHIFT];\n-\tbool ctrl  = keystate[SDLK_RCTRL]  || keystate[SDLK_LCTRL];\n-\tbool cmd   = keystate[SDLK_RMETA]  || keystate[SDLK_LMETA];\n-\tbool alt   = keystate[SDLK_RALT]   || keystate[SDLK_LALT];\n+\tif (scopematch.none()) {\n+\t\treturn false;\n+\t}\n \n-\treturn get_hotkey(-1, event.which, event.button, -1, -1, shift, ctrl, cmd, alt);\n+\tret = mod_ == other->mod_ && bindings_equal_helper(other);\n+\n+\treturn ret;\n }\n \n-const hotkey_item& get_hotkey(const SDL_JoyHatEvent& event)\n+bool hotkey_base::matches(const SDL_Event &event) const\n {\n-\tCKey keystate;\n-\tbool shift = keystate[SDLK_RSHIFT] || keystate[SDLK_LSHIFT];\n-\tbool ctrl  = keystate[SDLK_RCTRL]  || keystate[SDLK_LCTRL];\n-\tbool cmd   = keystate[SDLK_RMETA]  || keystate[SDLK_LMETA];\n-\tbool alt   = keystate[SDLK_RALT]   || keystate[SDLK_LALT];\n+\tunsigned int mods = sdl_get_mods();\n \n-\treturn get_hotkey(-1, event.which, -1, event.hat, event.value, shift, ctrl, cmd, alt);\n-}\n+\tif (!hotkey::is_scope_active(hotkey::get_hotkey_command(get_command()).scope) ||\n+\t\t\t!active()) {\n+\t\treturn false;\n+\t}\n+\n+\tif ((mods != mod_)) {\n+\t\treturn false;\n+\t}\n \n+\treturn matches_helper(event);\n+}\n \n-const hotkey_item& get_hotkey(const SDL_MouseButtonEvent& event)\n+void hotkey_base::save(config& item) const\n {\n-\tCKey keystate;\n-\tbool shift = keystate[SDLK_RSHIFT] || keystate[SDLK_LSHIFT];\n-\tbool ctrl  = keystate[SDLK_RCTRL]  || keystate[SDLK_LCTRL];\n-\tbool cmd   = keystate[SDLK_RMETA]  || keystate[SDLK_LMETA];\n-\tbool alt   = keystate[SDLK_RALT]   || keystate[SDLK_LALT];\n+\titem[\"command\"] = get_command();\n \n-\treturn get_hotkey(event.which, -1, event.button, -1, -1, shift, ctrl, cmd, alt);\n-}\n+\titem[\"shift\"] = !!(mod_ & KMOD_SHIFT);\n+\titem[\"ctrl\"] = !!(mod_ & KMOD_CTRL);\n+#if SDL_VERSION_ATLEAST(2, 0, 0)\n+\titem[\"cmd\"] = !!(mod_ & KMOD_GUI);\n+#else\n+\titem[\"cmd\"] = !!(mod_ & KMOD_META);\n+#endif\n+\titem[\"alt\"] = !!(mod_ & KMOD_ALT);\n \n+\tsave_helper(item);\n+}\n \n-const hotkey_item& get_hotkey(const SDL_KeyboardEvent& event)\n+hotkey_ptr create_hotkey(const std::string &id, SDL_Event &event)\n {\n-\treturn get_hotkey(\n-#if SDL_VERSION_ATLEAST(2, 0, 0)\n-\t\t\tevent.keysym.scancode,\n+\thotkey_ptr base = hotkey_ptr(new hotkey_void);\n+\n+\tswitch (event.type) {\n+\tcase SDL_KEYDOWN:\n+\tcase SDL_KEYUP: {\n+\t\thotkey_keyboard_ptr keyboard(new hotkey_keyboard());\n+\t\tbase = boost::dynamic_pointer_cast<hotkey_base>(keyboard);\n+\t\tSDL_Scancode code;\n+#if  SDL_VERSION_ATLEAST(2, 0, 0)\n+\t\tcode = event.key.keysym.scancode;\n #else\n-\t\t\tevent.keysym.unicode,\n+\t\tcode = SDL_GetScancodeFromKey(event.key.keysym.sym);\n #endif\n-\t\t\tevent.keysym.sym,\n-\t\t\t(event.keysym.mod & KMOD_SHIFT) != 0,\n-\t\t\t(event.keysym.mod & KMOD_CTRL)  != 0,\n-\t\t\t(event.keysym.mod & KMOD_META)  != 0,\n-\t\t\t(event.keysym.mod & KMOD_ALT)   != 0\n-\t\t\t);\n+\t\tkeyboard->set_scancode(code);\n+\t\tbreak;\n+\t}\n+\tcase SDL_MOUSEBUTTONDOWN:\n+\tcase SDL_MOUSEBUTTONUP: {\n+\t\thotkey_mouse_ptr mouse(new hotkey_mouse());\n+\t\tbase = boost::dynamic_pointer_cast<hotkey_base>(mouse);\n+\t\tmouse->set_button(event.button.button);\n+\t\tbreak;\n+\t}\n+\tdefault:\n+\t\tERR_G<< \"Trying to bind an unknown event type:\" << event.type << \"\\n\";\n+\t\tbreak;\n+\t}\n+\n+\tbase->set_mods(sdl_get_mods());\n+\tbase->set_command(id);\n+\tbase->unset_default();\n+\n+\treturn base;\n }\n \n+hotkey_ptr load_from_config(const config& cfg)\n+{\n+\thotkey_ptr base = hotkey_ptr(new hotkey_void());\n+\n+\tconst std::string& mouse_cfg = cfg[\"mouse\"];\n+\tif (!mouse_cfg.empty()) {\n+\t\thotkey_mouse_ptr mouse(new hotkey_mouse());\n+\t\tbase = boost::dynamic_pointer_cast<hotkey_base>(mouse);\n+\t\tmouse->set_button(cfg[\"button\"].to_int());\n+\t}\n+\t// TODO: add joystick support back\n+#if 0\n+\tconst std::string& joystick_cfg = cfg[\"joystick\"];\n+\tif (!joystick_cfg.empty()) {\n+\t\tjoystick_ = cfg[\"joystick\"].to_int();\n+\t}\n+\tconst std::string& hat = cfg[\"hat\"];\n+\tif (!hat.empty()) {\n+\t\that_ = cfg[\"hat\"].to_int();\n+\t\tvalue_ = cfg[\"value\"].to_int();\n+\t}\n \n+\tconst std::string& button = cfg[\"button\"];\n+\tif (!button.empty()) {\n+\t\tbutton_ = cfg[\"button\"].to_int();\n+\t}\n+#endif\n \n-std::string get_names(std::string id) {\n+\tconst std::string& key_cfg = cfg[\"key\"];\n+\tif (!key_cfg.empty()) {\n+\t\thotkey_keyboard_ptr keyboard(new hotkey_keyboard());\n+\t\tbase = boost::dynamic_pointer_cast<hotkey_base>(keyboard);\n \n-\tstd::vector<std::string> names;\n-\tBOOST_FOREACH(const hotkey::hotkey_item& item, hotkeys_) {\n-\t\tif (item.get_command() == id && (!item.null()) ) {\n-\t\t\tnames.push_back(item.get_name());\n+\t\tSDL_Scancode scancode = SDL_GetScancodeFromName(key_cfg.c_str());\n+\t\tif (scancode == SDL_SCANCODE_UNKNOWN) {\n+\t\t\tERR_G<< \"Unknown key: \" << key_cfg << \"\\n\";\n \t\t}\n+\t\tkeyboard->set_scancode(scancode);\n+\t}\n+\t\n+\t// These are hard-coded, non-rebindable hotkeys\n+\tif(id == \"quit\") {","path":"src/hotkey/hotkey_item.cpp","position":371,"original_position":371,"commit_id":"f5890a4f16738e479640e40c34e5b455d0441a0a","original_commit_id":"438740406f55373aec8545d309b4dcb2573894dd","user":{"login":"aginor","id":51365,"avatar_url":"https://avatars.githubusercontent.com/u/51365?v=3","gravatar_id":"","url":"https://api.github.com/users/aginor","html_url":"https://github.com/aginor","followers_url":"https://api.github.com/users/aginor/followers","following_url":"https://api.github.com/users/aginor/following{/other_user}","gists_url":"https://api.github.com/users/aginor/gists{/gist_id}","starred_url":"https://api.github.com/users/aginor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aginor/subscriptions","organizations_url":"https://api.github.com/users/aginor/orgs","repos_url":"https://api.github.com/users/aginor/repos","events_url":"https://api.github.com/users/aginor/events{/privacy}","received_events_url":"https://api.github.com/users/aginor/received_events","type":"User","site_admin":false},"body":"I think something horrible happened here when you rebased. Is this snippet of code supposed to be in get_names() instead? There should also be a space between the if and the opening bracket to fit into the style in the rest of the file.","created_at":"2015-09-08T10:21:24Z","updated_at":"2015-09-08T10:21:24Z","html_url":"https://github.com/wesnoth/wesnoth/pull/475#discussion_r38910299","pull_request_url":"https://api.github.com/repos/wesnoth/wesnoth/pulls/475","_links":{"self":{"href":"https://api.github.com/repos/wesnoth/wesnoth/pulls/comments/38910299"},"html":{"href":"https://github.com/wesnoth/wesnoth/pull/475#discussion_r38910299"},"pull_request":{"href":"https://api.github.com/repos/wesnoth/wesnoth/pulls/475"}}},"pull_request":{"url":"https://api.github.com/repos/wesnoth/wesnoth/pulls/475","id":43330086,"html_url":"https://github.com/wesnoth/wesnoth/pull/475","diff_url":"https://github.com/wesnoth/wesnoth/pull/475.diff","patch_url":"https://github.com/wesnoth/wesnoth/pull/475.patch","issue_url":"https://api.github.com/repos/wesnoth/wesnoth/issues/475","number":475,"state":"open","locked":false,"title":"Allow exiting map editor with Esc and show some non-rebindable keystrokes","user":{"login":"CelticMinstrel","id":578731,"avatar_url":"https://avatars.githubusercontent.com/u/578731?v=3","gravatar_id":"","url":"https://api.github.com/users/CelticMinstrel","html_url":"https://github.com/CelticMinstrel","followers_url":"https://api.github.com/users/CelticMinstrel/followers","following_url":"https://api.github.com/users/CelticMinstrel/following{/other_user}","gists_url":"https://api.github.com/users/CelticMinstrel/gists{/gist_id}","starred_url":"https://api.github.com/users/CelticMinstrel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CelticMinstrel/subscriptions","organizations_url":"https://api.github.com/users/CelticMinstrel/orgs","repos_url":"https://api.github.com/users/CelticMinstrel/repos","events_url":"https://api.github.com/users/CelticMinstrel/events{/privacy}","received_events_url":"https://api.github.com/users/CelticMinstrel/received_events","type":"User","site_admin":false},"body":"This supercedes #467 - instead of hacking into the event handling to process SDL_QUIT, I have modified the terminate method to pass the key event into the SDL event queue (instead of pushing a quit event). This does have the weird side-effect that the OSX menu will lie about the key shortcut if someone decides to reassign Cmd+Q to something else, but I think that's probably not a major issue.\r\n\r\nAlso, unlike #467, this does not change the behaviour of clicking the close button on the window decorations. Since the main issue stems from how Cmd+Q is easy to hit by mistake, I don't think that's a major problem. Furthermore, Cmd+Q now does nothing while a dialog is up, which also differs from both #467 (where I attempted to have a confirmation in that event) and original behaviour (instant quit), but I think this actually makes sense - most apps can't be quit while a modal dialog is open.\r\n\r\nThere is one thing here that I'm not quite sure how to deal with - in SDLmain.m, I have constructed a pair of key events and pushed them into the SDL event queue, but I wonder if there's a better way to do this. In particular, the scancode probably shouldn't be -1 (aka 255) and it would be good if it could properly pass on which of the two command keys was pressed (though in practice the latter probably won't matter).","created_at":"2015-08-25T20:05:33Z","updated_at":"2015-09-08T10:21:24Z","closed_at":null,"merged_at":null,"merge_commit_sha":"877b11d5be91309e8e99420c0472fb535c660de4","assignee":{"login":"aginor","id":51365,"avatar_url":"https://avatars.githubusercontent.com/u/51365?v=3","gravatar_id":"","url":"https://api.github.com/users/aginor","html_url":"https://github.com/aginor","followers_url":"https://api.github.com/users/aginor/followers","following_url":"https://api.github.com/users/aginor/following{/other_user}","gists_url":"https://api.github.com/users/aginor/gists{/gist_id}","starred_url":"https://api.github.com/users/aginor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aginor/subscriptions","organizations_url":"https://api.github.com/users/aginor/orgs","repos_url":"https://api.github.com/users/aginor/repos","events_url":"https://api.github.com/users/aginor/events{/privacy}","received_events_url":"https://api.github.com/users/aginor/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/wesnoth/wesnoth/pulls/475/commits","review_comments_url":"https://api.github.com/repos/wesnoth/wesnoth/pulls/475/comments","review_comment_url":"https://api.github.com/repos/wesnoth/wesnoth/pulls/comments{/number}","comments_url":"https://api.github.com/repos/wesnoth/wesnoth/issues/475/comments","statuses_url":"https://api.github.com/repos/wesnoth/wesnoth/statuses/f5890a4f16738e479640e40c34e5b455d0441a0a","head":{"label":"CelticMinstrel:quit-confirm2","ref":"quit-confirm2","sha":"f5890a4f16738e479640e40c34e5b455d0441a0a","user":{"login":"CelticMinstrel","id":578731,"avatar_url":"https://avatars.githubusercontent.com/u/578731?v=3","gravatar_id":"","url":"https://api.github.com/users/CelticMinstrel","html_url":"https://github.com/CelticMinstrel","followers_url":"https://api.github.com/users/CelticMinstrel/followers","following_url":"https://api.github.com/users/CelticMinstrel/following{/other_user}","gists_url":"https://api.github.com/users/CelticMinstrel/gists{/gist_id}","starred_url":"https://api.github.com/users/CelticMinstrel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CelticMinstrel/subscriptions","organizations_url":"https://api.github.com/users/CelticMinstrel/orgs","repos_url":"https://api.github.com/users/CelticMinstrel/repos","events_url":"https://api.github.com/users/CelticMinstrel/events{/privacy}","received_events_url":"https://api.github.com/users/CelticMinstrel/received_events","type":"User","site_admin":false},"repo":{"id":40266501,"name":"wesnoth","full_name":"CelticMinstrel/wesnoth","owner":{"login":"CelticMinstrel","id":578731,"avatar_url":"https://avatars.githubusercontent.com/u/578731?v=3","gravatar_id":"","url":"https://api.github.com/users/CelticMinstrel","html_url":"https://github.com/CelticMinstrel","followers_url":"https://api.github.com/users/CelticMinstrel/followers","following_url":"https://api.github.com/users/CelticMinstrel/following{/other_user}","gists_url":"https://api.github.com/users/CelticMinstrel/gists{/gist_id}","starred_url":"https://api.github.com/users/CelticMinstrel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CelticMinstrel/subscriptions","organizations_url":"https://api.github.com/users/CelticMinstrel/orgs","repos_url":"https://api.github.com/users/CelticMinstrel/repos","events_url":"https://api.github.com/users/CelticMinstrel/events{/privacy}","received_events_url":"https://api.github.com/users/CelticMinstrel/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/CelticMinstrel/wesnoth","description":"Free, turn-based strategy game with a high fantasy theme, featuring both single-player, and online/hotseat multiplayer combat.","fork":true,"url":"https://api.github.com/repos/CelticMinstrel/wesnoth","forks_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/forks","keys_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/keys{/key_id}","collaborators_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/teams","hooks_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/hooks","issue_events_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/issues/events{/number}","events_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/events","assignees_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/assignees{/user}","branches_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/branches{/branch}","tags_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/tags","blobs_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/git/refs{/sha}","trees_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/git/trees{/sha}","statuses_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/statuses/{sha}","languages_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/languages","stargazers_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/stargazers","contributors_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/contributors","subscribers_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/subscribers","subscription_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/subscription","commits_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/commits{/sha}","git_commits_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/git/commits{/sha}","comments_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/comments{/number}","issue_comment_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/issues/comments{/number}","contents_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/contents/{+path}","compare_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/compare/{base}...{head}","merges_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/merges","archive_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/downloads","issues_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/issues{/number}","pulls_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/pulls{/number}","milestones_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/milestones{/number}","notifications_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/labels{/name}","releases_url":"https://api.github.com/repos/CelticMinstrel/wesnoth/releases{/id}","created_at":"2015-08-05T20:07:50Z","updated_at":"2015-08-05T20:08:31Z","pushed_at":"2015-09-08T00:15:18Z","git_url":"git://github.com/CelticMinstrel/wesnoth.git","ssh_url":"git@github.com:CelticMinstrel/wesnoth.git","clone_url":"https://github.com/CelticMinstrel/wesnoth.git","svn_url":"https://github.com/CelticMinstrel/wesnoth","homepage":"http://www.wesnoth.org/","size":2284244,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"wesnoth:master","ref":"master","sha":"85a5c1c9c79af7e2567b5e9aefe6725b4331633f","user":{"login":"wesnoth","id":4024232,"avatar_url":"https://avatars.githubusercontent.com/u/4024232?v=3","gravatar_id":"","url":"https://api.github.com/users/wesnoth","html_url":"https://github.com/wesnoth","followers_url":"https://api.github.com/users/wesnoth/followers","following_url":"https://api.github.com/users/wesnoth/following{/other_user}","gists_url":"https://api.github.com/users/wesnoth/gists{/gist_id}","starred_url":"https://api.github.com/users/wesnoth/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wesnoth/subscriptions","organizations_url":"https://api.github.com/users/wesnoth/orgs","repos_url":"https://api.github.com/users/wesnoth/repos","events_url":"https://api.github.com/users/wesnoth/events{/privacy}","received_events_url":"https://api.github.com/users/wesnoth/received_events","type":"Organization","site_admin":false},"repo":{"id":9432220,"name":"wesnoth","full_name":"wesnoth/wesnoth","owner":{"login":"wesnoth","id":4024232,"avatar_url":"https://avatars.githubusercontent.com/u/4024232?v=3","gravatar_id":"","url":"https://api.github.com/users/wesnoth","html_url":"https://github.com/wesnoth","followers_url":"https://api.github.com/users/wesnoth/followers","following_url":"https://api.github.com/users/wesnoth/following{/other_user}","gists_url":"https://api.github.com/users/wesnoth/gists{/gist_id}","starred_url":"https://api.github.com/users/wesnoth/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wesnoth/subscriptions","organizations_url":"https://api.github.com/users/wesnoth/orgs","repos_url":"https://api.github.com/users/wesnoth/repos","events_url":"https://api.github.com/users/wesnoth/events{/privacy}","received_events_url":"https://api.github.com/users/wesnoth/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wesnoth/wesnoth","description":"Free, turn-based strategy game with a high fantasy theme, featuring both single-player, and online/hotseat multiplayer combat.","fork":false,"url":"https://api.github.com/repos/wesnoth/wesnoth","forks_url":"https://api.github.com/repos/wesnoth/wesnoth/forks","keys_url":"https://api.github.com/repos/wesnoth/wesnoth/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wesnoth/wesnoth/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wesnoth/wesnoth/teams","hooks_url":"https://api.github.com/repos/wesnoth/wesnoth/hooks","issue_events_url":"https://api.github.com/repos/wesnoth/wesnoth/issues/events{/number}","events_url":"https://api.github.com/repos/wesnoth/wesnoth/events","assignees_url":"https://api.github.com/repos/wesnoth/wesnoth/assignees{/user}","branches_url":"https://api.github.com/repos/wesnoth/wesnoth/branches{/branch}","tags_url":"https://api.github.com/repos/wesnoth/wesnoth/tags","blobs_url":"https://api.github.com/repos/wesnoth/wesnoth/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wesnoth/wesnoth/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wesnoth/wesnoth/git/refs{/sha}","trees_url":"https://api.github.com/repos/wesnoth/wesnoth/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wesnoth/wesnoth/statuses/{sha}","languages_url":"https://api.github.com/repos/wesnoth/wesnoth/languages","stargazers_url":"https://api.github.com/repos/wesnoth/wesnoth/stargazers","contributors_url":"https://api.github.com/repos/wesnoth/wesnoth/contributors","subscribers_url":"https://api.github.com/repos/wesnoth/wesnoth/subscribers","subscription_url":"https://api.github.com/repos/wesnoth/wesnoth/subscription","commits_url":"https://api.github.com/repos/wesnoth/wesnoth/commits{/sha}","git_commits_url":"https://api.github.com/repos/wesnoth/wesnoth/git/commits{/sha}","comments_url":"https://api.github.com/repos/wesnoth/wesnoth/comments{/number}","issue_comment_url":"https://api.github.com/repos/wesnoth/wesnoth/issues/comments{/number}","contents_url":"https://api.github.com/repos/wesnoth/wesnoth/contents/{+path}","compare_url":"https://api.github.com/repos/wesnoth/wesnoth/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wesnoth/wesnoth/merges","archive_url":"https://api.github.com/repos/wesnoth/wesnoth/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wesnoth/wesnoth/downloads","issues_url":"https://api.github.com/repos/wesnoth/wesnoth/issues{/number}","pulls_url":"https://api.github.com/repos/wesnoth/wesnoth/pulls{/number}","milestones_url":"https://api.github.com/repos/wesnoth/wesnoth/milestones{/number}","notifications_url":"https://api.github.com/repos/wesnoth/wesnoth/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wesnoth/wesnoth/labels{/name}","releases_url":"https://api.github.com/repos/wesnoth/wesnoth/releases{/id}","created_at":"2013-04-14T17:13:06Z","updated_at":"2015-09-08T06:32:37Z","pushed_at":"2015-09-08T09:28:05Z","git_url":"git://github.com/wesnoth/wesnoth.git","ssh_url":"git@github.com:wesnoth/wesnoth.git","clone_url":"https://github.com/wesnoth/wesnoth.git","svn_url":"https://github.com/wesnoth/wesnoth","homepage":"http://www.wesnoth.org/","size":2439554,"stargazers_count":647,"watchers_count":647,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":227,"mirror_url":null,"open_issues_count":23,"forks":227,"open_issues":23,"watchers":647,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/wesnoth/wesnoth/pulls/475"},"html":{"href":"https://github.com/wesnoth/wesnoth/pull/475"},"issue":{"href":"https://api.github.com/repos/wesnoth/wesnoth/issues/475"},"comments":{"href":"https://api.github.com/repos/wesnoth/wesnoth/issues/475/comments"},"review_comments":{"href":"https://api.github.com/repos/wesnoth/wesnoth/pulls/475/comments"},"review_comment":{"href":"https://api.github.com/repos/wesnoth/wesnoth/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/wesnoth/wesnoth/pulls/475/commits"},"statuses":{"href":"https://api.github.com/repos/wesnoth/wesnoth/statuses/f5890a4f16738e479640e40c34e5b455d0441a0a"}}}}